View Javadoc

1   /*
2    * Copyright 2004-2005 OSOCO.org (Carsten Ziegeler)
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.osoco.cowarp.portal.transformation;
17  
18  import java.io.IOException;
19  import java.util.Map;
20  
21  import org.apache.avalon.framework.parameters.Parameters;
22  import org.apache.cocoon.ProcessingException;
23  import org.apache.cocoon.environment.SourceResolver;
24  import org.apache.cocoon.portal.coplet.CopletInstanceData;
25  import org.apache.cocoon.portal.transformation.AbstractCopletTransformer;
26  import org.apache.cocoon.portal.transformation.CopletTransformer;
27  import org.apache.cocoon.xml.AttributesImpl;
28  import org.apache.excalibur.source.SourceUtil;
29  import org.xml.sax.Attributes;
30  import org.xml.sax.SAXException;
31  
32  /***
33   * A new transformer that is not finished yet.
34   *
35   * @author <a href="mailto:cziegeler.at.osoco.org">Carsten Ziegeler</a>
36   *
37   * @version CVS $Id: HTMLEventTransformer.java,v 1.6 2005/02/21 10:33:00 cziegeler Exp $
38   */
39  public class HTMLEventTransformer
40      extends AbstractCopletTransformer {
41  
42      /***
43       * Default namespace prefix.
44       */
45      public static final String NAMESPACE_PREFIX = "ct";
46  
47      /***
48       * Default prefix for links to resources (images etc.).
49       */
50      public static final String LINK_PREFIX = "htmllink-";
51  
52      /***
53       * The coplet instance data.
54       */
55      protected CopletInstanceData copletInstanceData;
56  
57      /*** The prefix for the generated link events. */
58      protected String namespacePrefix;
59  
60      /*** The namespace for the generated link events. */
61      protected String namespace;
62  
63      /*** The prefix for links to resources. */
64      protected String linkPrefix;
65  
66      /*** The temporary attribute used to store the uri. */
67      protected String attributeName;
68  
69      /*** The jxpath for the attribute. */
70      protected String jxPath;
71  
72      /*** Rewrite absolut links. */
73      protected boolean rewriteAbsoluteLinks;
74  
75      /* (non-Javadoc)
76       * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver, java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters)
77       */
78      public void setup(final SourceResolver resolver,
79                        final Map objectModel,
80                        final String src,
81                        final Parameters par)
82      throws ProcessingException, SAXException, IOException {
83          this.copletInstanceData = this.getCopletInstanceData();
84          this.namespacePrefix = par.getParameter("ns-prefix", NAMESPACE_PREFIX);
85          this.namespace = par.getParameter("namespace", CopletTransformer.NAMESPACE_URI);
86          this.linkPrefix = par.getParameter("prefix", LINK_PREFIX);
87  
88          this.attributeName = par.getParameter("attribute-name", "application-uri");
89          this.jxPath = "temporaryAttributes/" + this.attributeName;
90          this.rewriteAbsoluteLinks = par.getParameterAsBoolean("rewrite-absolute-links", true);
91      }
92  
93      /* (non-Javadoc)
94       * @see org.apache.avalon.excalibur.pool.Recyclable#recycle()
95       */
96      public void recycle() {
97          super.recycle();
98          this.copletInstanceData = null;
99          this.namespacePrefix = null;
100         this.namespace = null;
101         this.linkPrefix = null;
102         this.attributeName = null;
103         this.jxPath = null;
104     }
105 
106     /* (non-Javadoc)
107      * @see org.xml.sax.ContentHandler#startDocument()
108      */
109     public void startDocument() throws SAXException {
110         super.startDocument();
111         super.startPrefixMapping(this.namespacePrefix, this.namespace);
112     }
113 
114     /* (non-Javadoc)
115      * @see org.xml.sax.ContentHandler#endDocument()
116      */
117     public void endDocument() throws SAXException {
118         super.endPrefixMapping(this.namespacePrefix);
119         super.endDocument();
120     }
121 
122     /* (non-Javadoc)
123      * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
124      */
125     public void startElement(final String uri, final String name, final String raw,
126                              final Attributes attributes)
127     throws SAXException {
128 
129         Attributes converted = attributes;
130 
131         if ("form".equalsIgnoreCase(name)) {
132             converted = this.handleTag("action", attributes, (attributes.getIndex("target") > -1), "html-form");
133         } else if ("script".equalsIgnoreCase(name)) {
134             converted = this.handleTag("src", attributes, false, null);
135         } else if ("img".equalsIgnoreCase(name)) {
136             converted = this.handleTag("src", attributes, false, null);
137         } else if ("a".equalsIgnoreCase(name)) {
138             converted = this.handleTag("href", attributes, (attributes.getIndex("target") > -1), "html-link");
139         } else if ("input".equalsIgnoreCase(name)) {
140             converted = this.handleTag("src", attributes, false, null);
141         } else if ("applet".equalsIgnoreCase(name) && attributes.getIndex("codebase") > -1) {
142             converted = this.handleTag("codebase", attributes, true, null);
143         }
144 
145         if (converted == null) {
146             this.stack.push(Boolean.TRUE);
147         } else {
148             this.stack.push(Boolean.FALSE);
149             super.startElement(uri, name, raw, converted);
150         }
151     }
152 
153     /* (non-Javadoc)
154      * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
155      */
156     public void endElement(final String uri, final String name, final String raw)
157     throws SAXException {
158         Boolean rewrite = (Boolean)stack.pop();
159         if ( rewrite.booleanValue() ) {
160             super.endElement(this.namespace,
161                              CopletTransformer.LINK_ELEM,
162                              this.namespacePrefix + ':' + CopletTransformer.LINK_ELEM);
163         } else {
164             super.endElement(uri, name, raw);
165         }
166     }
167 
168     /***
169      * Handle a link/reference.
170      * @param attributeName The name of the attribute.
171      * @param attributes    All attributes.
172      * @param direct        Should the link point directly to the resource.
173      * @param aFormat       The format used to create the link.
174      * @return              The new attributes set.
175      * @throws SAXException If something goes wrong.
176      */
177     public Attributes handleTag(final String     attributeName,
178                                 final Attributes attributes,
179                                 final boolean    direct,
180                                 final String     aFormat)
181     throws SAXException {
182         String format = aFormat;
183         String remoteURI = attributes.getValue(attributeName);
184 
185         final boolean needsRewrite = this.linkNeedsRewrite(remoteURI, attributes);
186         if ( !needsRewrite ) {
187             return attributes;
188         }
189         if (direct) {
190             remoteURI = this.getLink((String)this.copletInstanceData.getTemporaryAttribute(this.attributeName), remoteURI);
191             format = null;
192         } else {
193             if ( format == null ) {
194                 final StringBuffer uriBuffer = new StringBuffer(remoteURI.length());
195 
196                 uriBuffer.append(this.linkPrefix);
197 
198                 uriBuffer.append(remoteURI);
199 
200                 final int indexQuestion = remoteURI.indexOf("?");
201                 uriBuffer.append((indexQuestion == -1 ? '?' : '&'));
202                 uriBuffer.append(this.copletInstanceData.getId());
203                 uriBuffer.append('&');
204                 uriBuffer.append(this.getPortalService().getPortalName());
205 
206                 remoteURI = uriBuffer.toString();
207             } else {
208                 remoteURI = this.getLink((String)this.copletInstanceData.getTemporaryAttribute(this.attributeName), remoteURI);
209             }
210         }
211         // create a mutable copy of the attributes
212         final AttributesImpl eventAttributes;
213         if (attributes instanceof AttributesImpl) {
214             eventAttributes = (AttributesImpl) attributes;
215         } else {
216             eventAttributes = new AttributesImpl(attributes);
217         }
218         // rewrite the attribute value
219         final int index = eventAttributes.getIndex(attributeName);
220         eventAttributes.setValue(index, remoteURI);
221 
222         if (format != null) {
223             eventAttributes.addCDATAAttribute("path", this.jxPath);
224             eventAttributes.addCDATAAttribute("value", remoteURI);
225             eventAttributes.addCDATAAttribute("coplet", this.copletInstanceData.getId());
226             eventAttributes.addCDATAAttribute("format", format);
227 
228             super.startElement(this.namespace,
229                                CopletTransformer.LINK_ELEM,
230                                this.namespacePrefix + ':' + CopletTransformer.LINK_ELEM,
231                                attributes);
232             return null;
233         }
234         return eventAttributes;
235     }
236 
237     /***
238      * External links, anchors and links like mailto or links using
239      * different protocols like ftp are not rewritten.
240      *
241      * @param link The original link.
242      * @param attributes attributes of the node.
243      * @return true if the link should be rewritten.
244      */
245     protected boolean linkNeedsRewrite(final String link, final Attributes attributes) {
246         // links to external documents will not be transformed to portal links
247         final String external = attributes.getValue("external");
248         if (external != null && external.trim().length() > 0
249             && external.trim().toLowerCase().equals ("true") ) {
250             return false;
251         }
252 
253         // links containing a local anchor or links pointing to ftp,
254         // javascript or mailto are not rewritten
255         if ( link == null
256              || link.startsWith("mailto:")
257              || link.startsWith("ftp://")
258              || link.startsWith("javascript:")
259              || link.startsWith("#") ) {
260             return false;
261         }
262 
263         // Check for absolute links (if the transformer is configured accordingly)
264         if ( !this.rewriteAbsoluteLinks ) {
265             if ( link.startsWith("http://") || link.startsWith("https://") ) {
266                 return false;
267             }
268         }
269 
270         return true;
271     }
272 
273     /***
274      * Absolutize the link.
275      * @param base  The base for the relative link
276      * @param link  The relative link
277      * @return The absolute link
278      */
279     protected String getLink(final String base, final String link) {
280         final String v = SourceUtil.absolutize(base, link);
281         return v;
282     }
283 
284 }