1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package io.wcm.handler.url.rewriter.impl;
21
22 import java.net.URLDecoder;
23 import java.nio.charset.StandardCharsets;
24
25 import org.apache.commons.lang3.StringUtils;
26 import org.apache.sling.rewriter.ProcessingComponentConfiguration;
27 import org.apache.sling.rewriter.ProcessingContext;
28 import org.apache.sling.rewriter.Transformer;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31 import org.xml.sax.Attributes;
32 import org.xml.sax.ContentHandler;
33 import org.xml.sax.Locator;
34 import org.xml.sax.SAXException;
35 import org.xml.sax.helpers.AttributesImpl;
36 import org.xml.sax.helpers.DefaultHandler;
37
38 import io.wcm.handler.url.UrlHandler;
39
40
41
42
43 class UrlExternalizerTransformer implements Transformer {
44
45 private UrlExternalizerTransformerConfig transformerConfig;
46 private ContentHandler contentHandler = EMPTY_CONTENT_HANDLER;
47 private UrlHandler urlHandler;
48
49 private static final Logger log = LoggerFactory.getLogger(UrlExternalizerTransformer.class.getName());
50 private static final ContentHandler EMPTY_CONTENT_HANDLER = new DefaultHandler();
51
52 @Override
53 public void init(ProcessingContext pipelineContext, ProcessingComponentConfiguration config) {
54 log.trace("Initialize UrlExternalizerTransformer with config: {}", config.getConfiguration());
55 transformerConfig = new UrlExternalizerTransformerConfig(config.getConfiguration());
56 urlHandler = pipelineContext.getRequest().adaptTo(UrlHandler.class);
57 }
58
59 @Override
60 public void setContentHandler(ContentHandler contentHandler) {
61 this.contentHandler = contentHandler;
62 }
63
64 @Override
65 @SuppressWarnings("PMD.UseStringBufferForStringAppends")
66 public void startElement(String nsUri, String name, String raw, Attributes attrs) throws SAXException {
67
68
69 String rewriteAttr = transformerConfig.getElementAttributeNames().get(name);
70 if (rewriteAttr == null) {
71 log.trace("Rewrite element {}: Skip - No rewrite attribute configured.", name);
72 contentHandler.startElement(nsUri, name, raw, attrs);
73 return;
74 }
75
76
77 if (urlHandler == null) {
78 log.warn("Rewrite element {}: Skip - Unable to get URL handler/Integrator handler instance.", name);
79 contentHandler.startElement(nsUri, name, raw, attrs);
80 return;
81 }
82
83
84 int attributeIndex = attrs.getIndex(rewriteAttr);
85 if (attributeIndex < 0) {
86 log.trace("Rewrite element {}: Skip - Attribute does not exist: {}", name, rewriteAttr);
87 contentHandler.startElement(nsUri, name, raw, attrs);
88 return;
89 }
90
91
92 String url = attrs.getValue(attributeIndex);
93 if (StringUtils.isEmpty(url)) {
94 log.trace("Rewrite element {}: Skip - URL is empty.", name);
95 contentHandler.startElement(nsUri, name, raw, attrs);
96 return;
97 }
98
99
100 String urlRemainder = null;
101 int urlRemainderPos = StringUtils.indexOfAny(url, '?', '#');
102 if (urlRemainderPos >= 0) {
103 urlRemainder = url.substring(urlRemainderPos);
104 url = url.substring(0, urlRemainderPos);
105 }
106
107
108 url = URLDecoder.decode(url, StandardCharsets.UTF_8);
109
110
111 String rewrittenUrl = urlHandler.get(url).buildExternalResourceUrl();
112 if (urlRemainder != null) {
113 if (rewrittenUrl == null) {
114 rewrittenUrl = urlRemainder;
115 }
116 else {
117 rewrittenUrl += urlRemainder;
118 }
119 }
120
121 if (StringUtils.equals(url, rewrittenUrl)) {
122 log.debug("Rewrite element {}: Skip - URL is already externalized: {}", name, url);
123 contentHandler.startElement(nsUri, name, raw, attrs);
124 return;
125 }
126
127
128 log.debug("Rewrite element {}: Rewrite URL {} to {}", name, url, rewrittenUrl);
129 AttributesImpl newAttrs = new AttributesImpl(attrs);
130 newAttrs.setValue(attributeIndex, rewrittenUrl);
131 contentHandler.startElement(nsUri, name, raw, newAttrs);
132 }
133
134 @Override
135 public void setDocumentLocator(Locator locator) {
136 this.contentHandler.setDocumentLocator(locator);
137 }
138
139 @Override
140 public void startDocument() throws SAXException {
141 this.contentHandler.startDocument();
142 }
143
144 @Override
145 public void endDocument() throws SAXException {
146 this.contentHandler.endDocument();
147 }
148
149 @Override
150 public void startPrefixMapping(String prefix, String uri) throws SAXException {
151 this.contentHandler.startPrefixMapping(prefix, uri);
152 }
153
154 @Override
155 public void endPrefixMapping(String prefix) throws SAXException {
156 this.contentHandler.endPrefixMapping(prefix);
157 }
158
159 @Override
160 public void endElement(String uri, String localName, String qName) throws SAXException {
161 this.contentHandler.endElement(uri, localName, qName);
162 }
163
164 @Override
165 public void characters(char[] ch, int start, int length) throws SAXException {
166 this.contentHandler.characters(ch, start, length);
167 }
168
169 @Override
170 public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
171 this.contentHandler.ignorableWhitespace(ch, start, length);
172 }
173
174 @Override
175 public void processingInstruction(String target, String data) throws SAXException {
176 this.contentHandler.processingInstruction(target, data);
177 }
178
179 @Override
180 public void skippedEntity(String name) throws SAXException {
181 this.contentHandler.skippedEntity(name);
182 }
183
184 @Override
185 public void dispose() {
186
187 }
188
189 }