KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > lenya > cms > cocoon > transformation > LinkRewritingTransformer


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */

17 package org.apache.lenya.cms.cocoon.transformation;
18
19 import java.io.IOException JavaDoc;
20 import java.util.Map JavaDoc;
21 import org.apache.avalon.framework.parameters.Parameters;
22 import org.apache.avalon.framework.activity.Disposable;
23 import org.apache.avalon.framework.service.ServiceSelector;
24 import org.apache.cocoon.ProcessingException;
25 import org.apache.cocoon.environment.ObjectModelHelper;
26 import org.apache.cocoon.environment.Request;
27 import org.apache.cocoon.environment.SourceResolver;
28 import org.apache.cocoon.transformation.AbstractSAXTransformer;
29 import org.apache.lenya.ac.AccessControlException;
30 import org.apache.lenya.ac.AccessController;
31 import org.apache.lenya.ac.AccessControllerResolver;
32 import org.apache.lenya.ac.AccreditableManager;
33 import org.apache.lenya.ac.Authorizer;
34 import org.apache.lenya.ac.Policy;
35 import org.apache.lenya.ac.PolicyManager;
36 import org.apache.lenya.ac.impl.DefaultAccessController;
37 import org.apache.lenya.ac.impl.PolicyAuthorizer;
38 import org.apache.lenya.cms.publication.Document;
39 import org.apache.lenya.cms.publication.DocumentBuilder;
40 import org.apache.lenya.cms.publication.PageEnvelope;
41 import org.apache.lenya.cms.publication.PageEnvelopeFactory;
42 import org.apache.lenya.cms.publication.Proxy;
43 import org.apache.lenya.cms.publication.Publication;
44 import org.apache.lenya.cms.publication.PublicationException;
45 import org.apache.lenya.util.ServletHelper;
46 import org.xml.sax.Attributes JavaDoc;
47 import org.xml.sax.SAXException JavaDoc;
48 import org.xml.sax.helpers.AttributesImpl JavaDoc;
49
50 /**
51  * <p>
52  * Link rewriting transformer.
53  * </p>
54  *
55  * <p>
56  * This transformer is applied to an XHMTL document. It processes <code>&lt;xhtml:a HREF="..."&gt;</code>
57  * attributes of the following form:
58  * </p>
59  * <p>
60  * <code>{context-prefix}/{publication-id}/{area}{document-url}</code>
61  * </p>
62  * <p>
63  * These links are rewritten using the following rules:
64  * </p>
65  * <ul>
66  * <li>The area is replaced by the current area (obtained from the page envelope).</li>
67  * <li>A URL prefix is added depending on the proxy configuration of the publication.</li>
68  * <li>If the target document does not exist, the <code>&lt;a/&gt;</code> element is removed to disable the link.</li>
69  * </ul>
70  *
71  * $Id: LinkRewritingTransformer.java,v 1.7 2004/03/16 11:12:16 gregor
72  */

73 public class LinkRewritingTransformer extends AbstractSAXTransformer implements Disposable {
74
75     private boolean ignoreAElement = false;
76     private ServiceSelector serviceSelector;
77     private PolicyManager policyManager;
78     private AccessControllerResolver acResolver;
79     private AccreditableManager accreditableManager;
80
81     private Document currentDocument;
82
83     /**
84      * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver,
85      * java.util.Map, java.lang.String,
86      * org.apache.avalon.framework.parameters.Parameters)
87      */

88     public void setup(SourceResolver resolver, Map JavaDoc objectModel, String JavaDoc source, Parameters parameters)
89             throws ProcessingException, SAXException JavaDoc, IOException JavaDoc {
90         super.setup(resolver, objectModel, source, parameters);
91
92         try {
93             PageEnvelope envelope = PageEnvelopeFactory.getInstance().getPageEnvelope(objectModel);
94             this.currentDocument = envelope.getDocument();
95
96         } catch (Exception JavaDoc e) {
97             throw new ProcessingException(e);
98         }
99
100         if (getLogger().isDebugEnabled()) {
101             getLogger().debug("Setting up transformer");
102             getLogger().debug(" Processed version: [" + getCurrentDocument() + "]");
103         }
104
105         Request request = ObjectModelHelper.getRequest(objectModel);
106
107         this.serviceSelector = null;
108         this.acResolver = null;
109         this.policyManager = null;
110
111         try {
112             this.serviceSelector = (ServiceSelector) this.manager
113                     .lookup(AccessControllerResolver.ROLE + "Selector");
114             this.acResolver = (AccessControllerResolver) this.serviceSelector
115                     .select(AccessControllerResolver.DEFAULT_RESOLVER);
116
117             if (getLogger().isDebugEnabled()) {
118                 getLogger().debug(" Resolved AC resolver [" + this.acResolver + "]");
119             }
120             String JavaDoc webappUrl = ServletHelper.getWebappURI(request);
121             AccessController accessController = this.acResolver.resolveAccessController(webappUrl);
122             if (accessController instanceof DefaultAccessController) {
123                 DefaultAccessController defaultAccessController = (DefaultAccessController) accessController;
124                 this.accreditableManager = defaultAccessController.getAccreditableManager();
125                 Authorizer[] authorizers = defaultAccessController.getAuthorizers();
126                 for (int i = 0; i < authorizers.length; i++) {
127                     if (authorizers[i] instanceof PolicyAuthorizer) {
128                         PolicyAuthorizer policyAuthorizer = (PolicyAuthorizer) authorizers[i];
129                         this.policyManager = policyAuthorizer.getPolicyManager();
130                     }
131                 }
132             }
133             if (getLogger().isDebugEnabled()) {
134                 getLogger().debug(" Using policy manager [" + this.policyManager + "]");
135             }
136         } catch (Exception JavaDoc e) {
137             throw new ProcessingException(e);
138         }
139     }
140
141     /**
142      * Returns the currently processed document.
143      *
144      * @return A document.
145      */

146     protected Document getCurrentDocument() {
147         return this.currentDocument;
148     }
149
150     /**
151      * The local name of the HTML &lt;a&gt; href attribute.
152      */

153     public static final String JavaDoc ATTRIBUTE_HREF = "href";
154
155     private String JavaDoc indent = "";
156
157     /**
158      * (non-Javadoc)
159      *
160      * @see org.xml.sax.ContentHandler#startElement(java.lang.String,
161      * java.lang.String, java.lang.String, org.xml.sax.Attributes)
162      */

163     public void startElement(String JavaDoc uri, String JavaDoc name, String JavaDoc qname, Attributes JavaDoc attrs)
164             throws SAXException JavaDoc {
165
166         if (getLogger().isDebugEnabled()) {
167             getLogger().debug(this.indent + "<" + qname + "> (ignoreAElement = "
168                     + isIgnoreAElement() + ")");
169             this.indent += " ";
170         }
171
172         AttributesImpl JavaDoc newAttrs = null;
173         if (lookingAtLinkElement(name)) {
174
175             setIgnoreAElement(false);
176
177             String JavaDoc href = attrs.getValue(ATTRIBUTE_HREF);
178             if (href != null) {
179
180                 Publication publication = getCurrentDocument().getPublication();
181                 DocumentBuilder builder = publication.getDocumentBuilder();
182
183                 try {
184
185                     newAttrs = new AttributesImpl JavaDoc(attrs);
186
187                     if (getLogger().isDebugEnabled()) {
188                         getLogger().debug(this.indent + "href URL: [" + href + "]");
189                     }
190
191                     String JavaDoc context = this.request.getContextPath();
192
193                     if (href.startsWith(context + "/" + publication.getId())) {
194
195                         final String JavaDoc webappUrlWithQueryString = href.substring(context.length());
196                         String JavaDoc webappUrlWithAnchor;
197                         
198                         String JavaDoc queryString = null;
199                         int queryStringIndex = webappUrlWithQueryString.indexOf("?");
200                         if (queryStringIndex > -1) {
201                             webappUrlWithAnchor = webappUrlWithQueryString.substring(0, queryStringIndex);
202                             queryString = webappUrlWithQueryString.substring(queryStringIndex + 1);
203                         }
204                         else {
205                             webappUrlWithAnchor = webappUrlWithQueryString;
206                         }
207                         
208                         String JavaDoc anchor = null;
209                         String JavaDoc webappUrl = null;
210                         
211                         int anchorIndex = webappUrlWithAnchor.indexOf("#");
212                         if (anchorIndex > -1) {
213                             webappUrl = webappUrlWithAnchor.substring(0, anchorIndex);
214                             anchor = webappUrlWithAnchor.substring(anchorIndex + 1);
215                         }
216                         else {
217                             webappUrl = webappUrlWithAnchor;
218                         }
219                         
220                         if (getLogger().isDebugEnabled()) {
221                             getLogger().debug(this.indent + "webapp URL: [" + webappUrl + "]");
222                             getLogger().debug(this.indent + "anchor: [" + anchor + "]");
223                         }
224                         if (builder.isDocument(publication, webappUrl)) {
225
226                             Document targetDocument = builder.buildDocument(publication, webappUrl);
227
228                             if (getLogger().isDebugEnabled()) {
229                                 getLogger().debug(this.indent + "Resolved target document: ["
230                                         + targetDocument + "]");
231                             }
232
233                             String JavaDoc currentAreaUrl = builder.buildCanonicalUrl(publication,
234                                     getCurrentDocument().getArea(),
235                                     targetDocument.getId(),
236                                     targetDocument.getLanguage());
237                             targetDocument = builder.buildDocument(publication, currentAreaUrl);
238
239                             if (targetDocument.exists()) {
240                                 rewriteLink(newAttrs, targetDocument, anchor, queryString);
241                             } else {
242                                 setIgnoreAElement(true);
243                             }
244                         }
245                     }
246                 } catch (Exception JavaDoc e) {
247                     getLogger().error("startElement failed: ", e);
248                     throw new SAXException JavaDoc(e);
249                 }
250             }
251
252         }
253
254         if (getLogger().isDebugEnabled()) {
255             getLogger().debug(this.indent + "ignoreAElement: " + isIgnoreAElement());
256         }
257
258         if (!(lookingAtAElement(name) && isIgnoreAElement())) {
259             if (newAttrs != null) {
260                 attrs = newAttrs;
261             }
262             super.startElement(uri, name, qname, attrs);
263             if (getLogger().isDebugEnabled()) {
264                 getLogger().debug(this.indent + "<" + qname + "> sent");
265             }
266         }
267     }
268
269     /**
270      * Rewrites a link.
271      *
272      * @param newAttrs The new attributes.
273      * @param targetDocument The target document.
274      * @param anchor The anchor (the string after the # character in the URL).
275      * @param queryString The query string without question mark.
276      * @throws AccessControlException when something went wrong.
277      * @throws PublicationException when something went wrong.
278      */

279     protected void rewriteLink(AttributesImpl JavaDoc newAttrs, Document targetDocument, String JavaDoc anchor, String JavaDoc queryString)
280             throws AccessControlException, PublicationException {
281         String JavaDoc webappUrl = targetDocument.getCompleteURL();
282         Policy policy = this.policyManager.getPolicy(this.accreditableManager, webappUrl);
283
284         Proxy proxy = targetDocument.getPublication().getProxy(targetDocument, policy.isSSLProtected());
285
286         String JavaDoc rewrittenURL;
287         if (proxy == null) {
288             rewrittenURL = this.request.getContextPath() + webappUrl;
289         } else {
290             rewrittenURL = proxy.getURL(targetDocument);
291         }
292         
293         if (anchor != null) {
294             rewrittenURL += "#" + anchor;
295         }
296
297         if (queryString != null) {
298             rewrittenURL += "?" + queryString;
299         }
300
301         if (getLogger().isDebugEnabled()) {
302             getLogger().debug(this.indent + "SSL protection: [" + policy.isSSLProtected() + "]");
303             getLogger().debug(this.indent + "Resolved proxy: [" + proxy + "]");
304             getLogger().debug(this.indent + "Rewriting URL to: [" + rewrittenURL + "]");
305         }
306
307         setHrefAttribute(newAttrs, rewrittenURL);
308     }
309
310     /**
311      * Sets the value of the href attribute.
312      *
313      * @param attr The attributes.
314      * @param value The value.
315      * @throws IllegalArgumentException if the href attribute is not contained
316      * in this attributes.
317      */

318     protected void setHrefAttribute(AttributesImpl JavaDoc attr, String JavaDoc value) {
319         int position = attr.getIndex(ATTRIBUTE_HREF);
320         if (position == -1) {
321             throw new IllegalArgumentException JavaDoc("The href attribute is not available!");
322         }
323         attr.setValue(position, value);
324     }
325
326     /**
327      * (non-Javadoc)
328      *
329      * @see org.xml.sax.ContentHandler#endElement(java.lang.String,
330      * java.lang.String, java.lang.String)
331      */

332     public void endElement(String JavaDoc uri, String JavaDoc name, String JavaDoc qname) throws SAXException JavaDoc {
333         if (getLogger().isDebugEnabled()) {
334             this.indent = this.indent.substring(2);
335             getLogger().debug(this.indent + "</" + qname + ">");
336         }
337         if (lookingAtAElement(name) && isIgnoreAElement()) {
338             setIgnoreAElement(false);
339         } else {
340             if (getLogger().isDebugEnabled()) {
341                 getLogger().debug(this.indent + "</" + qname + "> sent");
342             }
343             super.endElement(uri, name, qname);
344         }
345     }
346
347     /**
348      * Check if we are looking at a link element
349      *
350      * @param name name of the element
351      *
352      * @return true if we are looking at a link element
353      */

354     protected boolean lookingAtLinkElement(String JavaDoc name) {
355         return lookingAtAElement(name);
356     }
357
358     protected boolean lookingAtAElement(String JavaDoc name) {
359         return name.equals("a");
360     }
361
362     /**
363      * @see org.apache.avalon.framework.activity.Disposable#dispose()
364      */

365     public void dispose() {
366         if (getLogger().isDebugEnabled()) {
367             getLogger().debug("Disposing transformer");
368         }
369         if (this.serviceSelector != null) {
370             if (this.acResolver != null) {
371                 this.serviceSelector.release(this.acResolver);
372             }
373             this.manager.release(this.serviceSelector);
374         }
375     }
376
377     /**
378      * (non-Javadoc)
379      * @see org.apache.avalon.excalibur.pool.Recyclable#recycle()
380      */

381     public void recycle() {
382         this.ignoreAElement = false;
383     }
384     /**
385      * @return Returns the ignoreAElement.
386      */

387     protected boolean isIgnoreAElement() {
388         return ignoreAElement;
389     }
390     /**
391      * @param ignoreAElement The ignoreAElement to set.
392      */

393     protected void setIgnoreAElement(boolean ignoreAElement) {
394         this.ignoreAElement = ignoreAElement;
395     }
396 }
Popular Tags