Skip to main content

Legacy Site Redirects Filter

If your legacy URLs patterns are too complex for a Vanity Redirect, it may be simpler to handle these redirects in a Filter.

The logic to process these legacy URLs redirects will be different for every project, but here's an example to get you started.

This one handles two different use cases, which is not at all uncommon when migrating from a legacy site.

note

This code is an example only and will need customization by a developer before it is useful in a project.

1
import java.util.List;
2
import java.util.regex.Matcher;
3
import java.util.regex.Pattern;
4
import javax.servlet.Filter;
5
import javax.servlet.FilterChain;
6
import javax.servlet.http.HttpServletRequest;
7
import javax.servlet.http.HttpServletResponse;
8
9
import com.psddev.cms.db.Content;
10
import com.psddev.cms.db.PageFilter;
11
import com.psddev.dari.db.Predicate;
12
import com.psddev.dari.db.PredicateParser;
13
import com.psddev.dari.db.Query;
14
import com.psddev.dari.util.AbstractFilter;
15
16
/**
17
* Redirect Legacy URLs to the appropriate permalink.
18
*/
19
public class LegacyUrlRedirectFilter extends AbstractFilter implements AbstractFilter.Auto {
20
21
// Legacy URL was /story/normalized-headline/123456
22
// "/story" is the prefix
23
// "normalized-headline" can be ignored
24
// "123456" has been saved on every migrated object using the field "migration.legacyId" with a prefix of "story:"
25
private static final Pattern LEGACY_STORY_URI_PATTERN = Pattern.compile("^/story/[^/]+/(.*)$");
26
private static final String STORY_ID_PREFIX = "story:";
27
28
// Legacy section path was /section.php?id=789
29
// "789" has been saved on every migrated object using the field "migration.legacyId" with a prefix of "section:"
30
private static final String LEGACY_SECTION_PATH = "/section.php";
31
private static final String LEGACY_SECTION_ID_PARAMETER = "id";
32
private static final String SECTION_ID_PREFIX = "section:";
33
34
private static final String LEGACY_ID_FIELD = "migration.legacyId";
35
36
// Helper method to build legacy story ID predicate
37
private static Predicate legacyStoryIdPredicate(String storyId) {
38
return PredicateParser.Static.parse(LEGACY_ID_FIELD + " = ?", STORY_ID_PREFIX + storyId);
39
}
40
41
// Helper method to build legacy section ID predicate
42
private static Predicate legacySectionIdPredicate(String sectionId) {
43
return PredicateParser.Static.parse(LEGACY_ID_FIELD + " = ?", SECTION_ID_PREFIX + sectionId);
44
}
45
46
// Helper method to redirect
47
private static void sendRedirect(HttpServletResponse response, String location) {
48
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
49
response.setHeader("Location", location);
50
}
51
52
// This should run *before* PageFilter.
53
@Override
54
public void updateDependencies(Class<? extends AbstractFilter> filterClass, List<Class<? extends Filter>> dependencies) {
55
if (PageFilter.class == filterClass) {
56
dependencies.add(LegacyUrlRedirectFilter.class);
57
}
58
}
59
60
@Override
61
protected void doRequest(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws Exception {
62
63
Object mainObject = PageFilter.Static.getMainObject(request);
64
65
// Only run if a mainObject cannot be found
66
if (mainObject == null) {
67
String requestPath = request.getRequestURI();
68
69
// Attempt to match the legacy section path
70
if (LEGACY_SECTION_PATH.equals(requestPath)) {
71
String legacySectionId = request.getParameter(LEGACY_SECTION_ID_PARAMETER);
72
if (legacySectionId != null && !legacySectionId.isEmpty()) {
73
Content content = Query.from(Content.class)
74
.where(legacySectionIdPredicate(legacySectionId))
75
.first();
76
if (content != null) {
77
sendRedirect(response, content.getPermalink());
78
return;
79
}
80
}
81
}
82
83
// Attempt to match the legacy story path and extract the story ID from the path
84
Matcher storyPathMatcher = LEGACY_STORY_URI_PATTERN.matcher(requestPath);
85
if (storyPathMatcher.matches()) {
86
String legacyStoryId = storyPathMatcher.group(1);
87
if (legacyStoryId != null && !legacyStoryId.isEmpty()) {
88
Content content = Query.from(Content.class)
89
.where(legacyStoryIdPredicate(legacyStoryId))
90
.first();
91
if (content != null) {
92
sendRedirect(response, content.getPermalink());
93
return;
94
}
95
}
96
}
97
}
98
99
// Otherwise, continue processing the request.
100
chain.doFilter(request, response);
101
}
102
}