KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > portal > transformation > LinkTransformer


1 /*
2  * Copyright 1999-2002,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 package org.apache.cocoon.portal.transformation;
17
18 import java.io.IOException JavaDoc;
19 import java.net.MalformedURLException JavaDoc;
20 import java.util.Map JavaDoc;
21 import java.util.Stack JavaDoc;
22
23 import org.apache.avalon.framework.parameters.Parameters;
24 import org.apache.avalon.framework.service.ServiceException;
25 import org.apache.avalon.framework.service.ServiceManager;
26 import org.apache.avalon.framework.service.Serviceable;
27 import org.apache.cocoon.ProcessingException;
28 import org.apache.cocoon.environment.ObjectModelHelper;
29 import org.apache.cocoon.environment.SourceResolver;
30 import org.apache.cocoon.portal.Constants;
31 import org.apache.cocoon.portal.coplet.CopletInstanceData;
32 import org.apache.cocoon.transformation.AbstractTransformer;
33 import org.apache.cocoon.xml.AttributesImpl;
34 import org.xml.sax.Attributes JavaDoc;
35 import org.xml.sax.SAXException JavaDoc;
36
37 /**
38  * This Transformer deals with tags containing links to external applications that need to be converted so
39  * that not the external application will be called directly but the request gets routed via the cocoon portal
40  * (either via proxy transformer or proxy reader).
41  * The link transformer therefore cooperates with the event link transformer.
42  * Tags that include a link for which a link event needs to be generated will be converted to
43  * <eventlink> elements.
44  * Examples:<br><br>
45  *
46  * <pre>
47  * &lt;img SRC="images/logo.jpg"&gt; will be converted to use the proxy reader:
48  * &lt;img SRC="proxy-images/logo.jpg&cocoon-portal-copletid=xxx&cocoon-portal-portalname=yyy
49  * <br>
50  * &lt;form action="/submitted.jsp"&gt; will be converted to be processed by the event link transformer
51  * &lt;eventlink action="/submitted.jsp" attribute="action" element="form"&gt;
52  * </pre>
53  *
54  * @author <a HREF="mailto:gernot.koller@rizit.at">Gernot Koller</a>
55  * @author <a HREF="mailto:friedrich.klenner@rzb.at">Friedrich Klenner</a>
56  *
57  * @version CVS $Id: LinkTransformer.java 124364 2005-01-06 11:28:54Z cziegeler $
58  */

59 public class LinkTransformer
60     extends AbstractTransformer
61     implements Serviceable {
62
63     /**
64      * Namespace prefix usef vor NewEventLinkTransformer-Namespace
65      */

66     public static final String JavaDoc NAMESPACE_PREFIX = "ev";
67
68     /**
69      * Used for appending a request parameter containing the coplet id
70      */

71     protected String JavaDoc copletIdParamString;
72
73     /**
74      * Used for appending a request parameter containing the portal name
75      */

76     protected String JavaDoc portalNameParamString;
77
78     /**
79      * The coplet instance data
80      */

81     protected CopletInstanceData copletInstanceData;
82
83     /**
84      * The html document base uri
85      */

86     protected String JavaDoc documentBase;
87
88     /**
89      * Used to store elements' name between startTransformingElement and endTransformingElement.
90      */

91     protected Stack JavaDoc elementStack = new Stack JavaDoc();
92
93     /**
94      * The avalon service manager
95      */

96     protected ServiceManager manager;
97
98     /* (non-Javadoc)
99      * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
100      */

101     public void service(ServiceManager manager) throws ServiceException {
102         this.manager = manager;
103     }
104
105     /** The prefix */
106     protected String JavaDoc prefix;
107
108     /** Handle target self as no target? */
109     protected boolean ignoreTargetSelf;
110     
111     /**
112      * @see AbstractTransformer#setup(SourceResolver, Map, String, Parameters)
113      */

114     public void setup(SourceResolver resolver,
115                       Map JavaDoc objectModel,
116                       String JavaDoc src,
117                       Parameters par)
118     throws ProcessingException, SAXException JavaDoc, IOException JavaDoc {
119         this.ignoreTargetSelf = par.getParameterAsBoolean("ignore-target-self", false);
120         
121         this.copletInstanceData =
122             ProxyTransformer.getInstanceData(
123                 this.manager,
124                 objectModel,
125                 par);
126         this.copletIdParamString =
127             ProxyTransformer.COPLETID + "=" + copletInstanceData.getId();
128
129         Map JavaDoc context = (Map JavaDoc) objectModel.get(ObjectModelHelper.PARENT_CONTEXT);
130         this.portalNameParamString =
131             ProxyTransformer.PORTALNAME
132                 + "="
133                 + (String JavaDoc) context.get(Constants.PORTAL_NAME_KEY);
134         this.prefix = par.getParameter("prefix", ProxyTransformer.PROXY_PREFIX);
135     }
136
137     /**
138      * Recycle this component.
139      * All instance variables are set to <code>null</code>.
140      */

141     public void recycle() {
142         super.recycle();
143         this.copletInstanceData = null;
144         this.elementStack.clear();
145         this.copletIdParamString = null;
146         this.portalNameParamString = null;
147     }
148
149     /**
150      * @see org.xml.sax.ContentHandler#startDocument()
151      */

152     public void startDocument() throws SAXException JavaDoc {
153         super.startDocument();
154         documentBase =
155         (String JavaDoc)copletInstanceData.getAttribute(ProxyTransformer.DOCUMENT_BASE);
156         super.startPrefixMapping(NAMESPACE_PREFIX,
157                                  NewEventLinkTransformer.NAMESPACE_URI);
158     }
159
160     /**
161      * @see org.xml.sax.ContentHandler#endDocument()
162      */

163     public void endDocument() throws SAXException JavaDoc {
164         super.endPrefixMapping(NAMESPACE_PREFIX);
165         super.endDocument();
166     }
167
168     /**
169      * @see org.xml.sax.ContentHandler#startElement(String, String, String, Attributes)
170      */

171     public void startElement(String JavaDoc uri, String JavaDoc name, String JavaDoc raw,
172                              Attributes JavaDoc attributes)
173     throws SAXException JavaDoc {
174
175         if ("form".equalsIgnoreCase(name)) {
176             handleTag(
177                 "action",
178                 uri,
179                 name,
180                 raw,
181                 attributes,
182                 true,
183                 (attributes.getIndex("target") > -1));
184         } else if ("script".equalsIgnoreCase(name)) {
185             handleTag("src", uri, name, raw, attributes, false, false);
186         } else if ("img".equalsIgnoreCase(name)) {
187             handleTag("src", uri, name, raw, attributes, false, false);
188         } else if ("link".equalsIgnoreCase(name)) {
189             handleTag("href", uri, name, raw, attributes, false, false);
190         } else if ("a".equalsIgnoreCase(name)) {
191             boolean direct;
192             final String JavaDoc v = attributes.getValue("target");
193             if ( v == null || (this.ignoreTargetSelf && v.equals("self")) ) {
194                 direct = false;
195             } else {
196                 direct = true;
197             }
198             handleTag("href", uri, name, raw, attributes, true, direct);
199         } else if ("menu-item".equalsIgnoreCase(name)) {
200             handleTag("href", uri, name, raw, attributes, true, false);
201         } else if ("input".equalsIgnoreCase(name)) {
202             handleTag("src", uri, name, raw, attributes, false, false);
203         } else if ("applet".equalsIgnoreCase(name)) {
204             if (attributes.getIndex("codebase") > -1) {
205                 handleTag("codebase", uri, name, raw, attributes, false, true);
206             }
207         } else {
208             super.startElement(uri, name, raw, attributes);
209         }
210     }
211
212     /**
213      * @see org.xml.sax.ContentHandler#endElement(String, String, String)
214      */

215     public void endElement(String JavaDoc uri, String JavaDoc name, String JavaDoc raw)
216     throws SAXException JavaDoc {
217         String JavaDoc elementName = null;
218
219         if (!elementStack.empty()) {
220             elementName = (String JavaDoc) elementStack.peek();
221         }
222
223         if (elementName != null && elementName.equals(name)) {
224             elementStack.pop();
225             super.endElement(
226                 NewEventLinkTransformer.NAMESPACE_URI,
227                 NewEventLinkTransformer.EVENT_ELEM,
228                 NAMESPACE_PREFIX + ":" + NewEventLinkTransformer.EVENT_ELEM);
229         } else {
230             super.endElement(uri, name, raw);
231         }
232     }
233
234     /**
235      * The handleTag method is responsible for preparing tags so that they can either be conveted to
236      * link events by the event link transformer or that the proxy reader is called directly.
237      * Tags with absolute links (starting with "http://", "ftp://", etc.) will not be touched.
238      * Tags which contain a target attribute will be modified to call the uri directly
239      * (no proxy reader or proxy transformer involved).
240      * Tags (like &lt;a HREF="uri"&ht; or &lt;form action="uri"&gt, etc.) that require a link event will be converted to
241      * &lt;eventlink&gt; elements, so that the event link transformer can create the necessary link event
242      * and the proxy transformer will be used.
243      * Tags (like &lt;img SRC="uri"&gt;) that shoud call the proxy reader will be converted to do so.
244      *
245      * Examples:<br><br>
246      *
247      * <pre>
248      * &lt;a HREF="http://www.somewhere.com"&gt; will not be converted because of absolute url
249      * <br>
250      * &lt;img SRC="images/logo.jpg"&gt; will be converted to use the proxy reader:
251      * &lt;img SRC="proxy-images/logo.jpg&cocoon-portal-copletid=xxx&cocoon-portal-portalname=yyy
252      * <br>
253      * &lt;form action="/submitted.jsp"&gt; will be converted to use proxy transformer:
254      * &lt;eventlink action="/submitted.jsp" attribute="action" element="form"&gt;
255      * </pre>
256      *
257      * @param attributeName Name oft the attribute containing the link to be converted
258      * @param uri Namespace URI
259      * @param elementName Name of the element (tag)
260      * @param raw Raw name of the element (including namespace prefix)
261      * @param attributes Attributes of the element
262      * @param eventLink True signals that the tag sould be converted to an event link tag.
263      * @param direct True signals that the uri should point directly to the external resource (no proxys)
264      * @throws SAXException if an invalid URL was detected.
265      */

266     public void handleTag(String JavaDoc attributeName,
267                           String JavaDoc uri,
268                           String JavaDoc elementName,
269                           String JavaDoc raw,
270                           Attributes JavaDoc attributes,
271                           boolean eventLink,
272                           boolean direct)
273     throws SAXException JavaDoc {
274         String JavaDoc remoteURI = attributes.getValue(attributeName);
275
276         if ((remoteURI == null)
277             || remoteURI.startsWith("http://")
278             || remoteURI.startsWith("https://")
279             || remoteURI.startsWith("#")
280             || remoteURI.startsWith("ftp://")
281             || remoteURI.startsWith("javascript:")
282             || remoteURI.startsWith("mailto:")) {
283             super.startElement(uri, elementName, raw, attributes);
284         } else {
285             boolean evalTarget;
286             final String JavaDoc v = attributes.getValue("target");
287             if ( v == null || (this.ignoreTargetSelf && v.equals("self")) ) {
288                 evalTarget = false;
289             } else {
290                 evalTarget = true;
291             }
292             if (evalTarget || direct) {
293                 try {
294                     remoteURI =
295                         ProxyTransformer.resolveURI(remoteURI, documentBase);
296                     eventLink = false;
297                 } catch (MalformedURLException JavaDoc ex) {
298                     throw new SAXException JavaDoc(
299                         "Invalid URL encountered: " + remoteURI,
300                         ex);
301                 }
302             } else {
303                 remoteURI = this.buildUrlString(remoteURI, !eventLink);
304             }
305
306             Attributes JavaDoc newAttributes =
307                 modifyLinkAttribute(attributeName, remoteURI, attributes);
308
309             if (eventLink) {
310                 this.startEventLinkElement(
311                     elementName,
312                     attributeName,
313                     newAttributes);
314             } else {
315                 super.startElement(uri, elementName, raw, newAttributes);
316             }
317         }
318     }
319
320     /**
321      * Replaces the link of given attribute whith the new uri.
322      * @param attribute Name of the attribute containing the link
323      * @param remoteURI The new uri
324      * @param attributes List of attributes
325      * @return The modified List of attributes
326      */

327     protected Attributes JavaDoc modifyLinkAttribute(String JavaDoc attribute,
328                                              String JavaDoc remoteURI,
329                                              Attributes JavaDoc attributes) {
330         AttributesImpl newAttributes = new AttributesImpl(attributes);
331
332         int index = newAttributes.getIndex(attribute);
333         newAttributes.setValue(index, remoteURI);
334         return newAttributes;
335     }
336
337     /**
338      * Replaces the given element with an eventlink element adding the attribute and element attribute within
339      * the SAX stream.
340      * @param element Original name of the element
341      * @param attribute Name of the attribute containing the link
342      * @param attributes Original list of attributes
343      * @throws SAXException
344      */

345     protected void startEventLinkElement(String JavaDoc element,
346                                          String JavaDoc attribute,
347                                          Attributes JavaDoc attributes)
348     throws SAXException JavaDoc {
349         elementStack.push(element);
350         AttributesImpl eventAttributes = null;
351         if (attributes instanceof AttributesImpl) {
352             eventAttributes = (AttributesImpl) attributes;
353         } else {
354             eventAttributes = new AttributesImpl(attributes);
355         }
356         eventAttributes.addCDATAAttribute(NewEventLinkTransformer.ATTRIBUTE_ATTR, attribute);
357         eventAttributes.addCDATAAttribute(NewEventLinkTransformer.ELEMENT_ATTR, element);
358         eventAttributes.addCDATAAttribute("coplet", this.copletInstanceData.getId());
359
360         super.startElement(
361             NewEventLinkTransformer.NAMESPACE_URI,
362             NewEventLinkTransformer.EVENT_ELEM,
363             NAMESPACE_PREFIX + ":" + NewEventLinkTransformer.EVENT_ELEM,
364             eventAttributes);
365     }
366
367     /**
368      * Retrieves and stores any session token, appends proxy reader prefix and parameters if necessary
369      * @param uri the url to be converted
370      * @param applyPrefixAndPortalParams true signals that the url should be converted to call the proxy-reader
371      * @return the converted uri
372      * FIXME: anchors (#) should be treated right!
373      */

374     protected String JavaDoc buildUrlString(String JavaDoc uri,
375                                     boolean applyPrefixAndPortalParams) {
376         StringBuffer JavaDoc uriBuffer = new StringBuffer JavaDoc(uri.length());
377
378         int index_semikolon = uri.indexOf(";");
379         int index_question = uri.indexOf("?");
380
381         if ((index_semikolon > -1)) {
382             String JavaDoc sessionToken =
383                 uri.substring(
384                     index_semikolon + 1,
385                     (index_question == -1 ? uri.length() : index_question));
386             copletInstanceData.getPersistentAspectData().put(
387                 ProxyTransformer.SESSIONTOKEN,
388                 sessionToken);
389         }
390
391         if (applyPrefixAndPortalParams) {
392             uriBuffer.append(this.prefix);
393         }
394
395         uriBuffer.append(uri);
396
397         if (applyPrefixAndPortalParams) {
398             uriBuffer.append((index_question == -1 ? '?' : '&'));
399             uriBuffer.append(this.copletIdParamString);
400             uriBuffer.append('&');
401             uriBuffer.append(this.portalNameParamString);
402         }
403
404         return uriBuffer.toString();
405     }
406 }
Popular Tags