KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > transformation > FragmentExtractorTransformer


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 package org.apache.cocoon.transformation;
17
18 import java.io.IOException JavaDoc;
19 import java.io.Serializable JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.Map JavaDoc;
23
24 import org.apache.avalon.framework.activity.Disposable;
25 import org.apache.avalon.framework.configuration.Configurable;
26 import org.apache.avalon.framework.configuration.Configuration;
27 import org.apache.avalon.framework.configuration.ConfigurationException;
28 import org.apache.avalon.framework.parameters.Parameters;
29 import org.apache.avalon.framework.service.ServiceException;
30 import org.apache.avalon.framework.service.ServiceManager;
31 import org.apache.avalon.framework.service.Serviceable;
32
33 import org.apache.avalon.excalibur.pool.Recyclable;
34
35 import org.apache.cocoon.ProcessingException;
36 import org.apache.cocoon.caching.CacheableProcessingComponent;
37 import org.apache.cocoon.components.sax.XMLSerializer;
38 import org.apache.cocoon.environment.ObjectModelHelper;
39 import org.apache.cocoon.environment.SourceResolver;
40 import org.apache.cocoon.util.HashUtil;
41
42 import org.apache.excalibur.source.SourceValidity;
43 import org.apache.excalibur.source.impl.validity.NOPValidity;
44 import org.apache.excalibur.store.Store;
45
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  * The transformation half of the FragmentExtractor.
52  *
53  * This transformer recieves an incoming stream of xml and replaces
54  * fragments with an fragment extractor locator pointing to the fragments.
55  *
56  * The extracted fragments are identified by their element name and namespace URI.
57  * The default is to extract SVG images ("svg" elements in namespace
58  * "http://www.w3.org/2000/svg"), but this can be overriden in the configuration:
59  * <pre>
60  * &lt;extract-uri&gt;http://my/namespace/uri&lt;/extract-uri&gt;
61  * &lt;extract-element&gt;my-element&lt;/extract-element&gt;
62  * </pre>
63  *
64  * Fragment extractor locator format is following:
65  * <pre>
66  * &lt;fe:fragment xmlns:fe="http://apache.org/cocoon/fragmentextractor/2.0" fragment-id="..."/&gt;
67  * </pre>
68  *
69  * @author <a HREF="mailto:paul@luminas.co.uk">Paul Russell</a>
70  * @version CVS $Id: FragmentExtractorTransformer.java 224618 2005-07-24 13:42:15Z joerg $
71  */

72 public class FragmentExtractorTransformer extends AbstractTransformer
73     implements CacheableProcessingComponent, Configurable, Serviceable, Disposable, Recyclable {
74
75     public static final String JavaDoc FE_URI = "http://apache.org/cocoon/fragmentextractor/2.0";
76
77     private static final String JavaDoc EXTRACT_URI_NAME = "extract-uri";
78     private static final String JavaDoc EXTRACT_ELEMENT_NAME = "extract-element";
79
80     private static final String JavaDoc EXTRACT_URI = "http://www.w3.org/2000/svg";
81     private static final String JavaDoc EXTRACT_ELEMENT = "svg";
82
83     private String JavaDoc extractURI;
84     private String JavaDoc extractElement;
85
86     /** The ServiceManager instance */
87     protected ServiceManager manager;
88
89     private XMLSerializer serializer;
90
91     private Map JavaDoc prefixMap;
92
93     private int extractLevel;
94
95     private int fragmentID;
96
97     private String JavaDoc requestURI;
98
99     /**
100      * Configure this transformer.
101      */

102     public void configure(Configuration conf) throws ConfigurationException {
103         this.extractURI = conf.getChild(EXTRACT_URI_NAME).getValue(EXTRACT_URI);
104         this.extractElement = conf.getChild(EXTRACT_ELEMENT_NAME).getValue(EXTRACT_ELEMENT);
105         if (getLogger().isDebugEnabled()) {
106             getLogger().debug("Extraction URI is " + this.extractURI);
107             getLogger().debug("Extraction element is " + this.extractElement);
108         }
109     }
110
111     /**
112      * Set the current <code>ServiceManager</code> instance used by this
113      * <code>Serviceable</code>.
114      */

115     public void service(ServiceManager manager) throws ServiceException {
116         this.manager = manager;
117     }
118
119     /**
120      * Recycle this component
121      */

122     public void recycle() {
123         if (this.manager != null) {
124             this.manager.release(serializer);
125             this.serializer = null;
126         }
127         super.recycle();
128     }
129
130     /**
131      * Release all resources.
132      */

133     public void dispose() {
134         recycle();
135         this.manager = null;
136     }
137
138     /**
139      * Setup the transformer.
140      */

141     public void setup(SourceResolver resolver, Map JavaDoc objectModel, String JavaDoc src, Parameters parameters)
142     throws ProcessingException, SAXException JavaDoc, IOException JavaDoc {
143         extractLevel = 0;
144         fragmentID = 0;
145         prefixMap = new HashMap JavaDoc();
146
147         this.requestURI = ObjectModelHelper.getRequest(objectModel).getSitemapURI();
148     }
149
150     /**
151      * Generate the unique key.
152      * This key must be unique inside the space of this component.
153      *
154      * @return "1"
155      */

156     public Serializable JavaDoc getKey() {
157         return "1";
158     }
159
160     /**
161      * Generate the validity object.
162      *
163      * @return NOPValidity object
164      * - if the input is valid the output is valid as well.
165      */

166     public SourceValidity getValidity() {
167         return NOPValidity.SHARED_INSTANCE;
168     }
169
170     /**
171      * Begin the scope of a prefix-URI Namespace mapping.
172      *
173      * @param prefix The Namespace prefix being declared.
174      * @param uri The Namespace URI the prefix is mapped to.
175      */

176     public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
177     throws SAXException JavaDoc {
178         if (extractLevel == 0) {
179             super.startPrefixMapping(prefix, uri);
180             prefixMap.put(prefix, uri);
181         } else {
182             this.serializer.startPrefixMapping(prefix, uri);
183         }
184     }
185
186     /**
187      * End the scope of a prefix-URI mapping.
188      *
189      * @param prefix The prefix that was being mapping.
190      */

191     public void endPrefixMapping(String JavaDoc prefix)
192     throws SAXException JavaDoc {
193         if (extractLevel == 0) {
194             super.endPrefixMapping(prefix);
195             prefixMap.remove(prefix);
196         } else {
197             this.serializer.endPrefixMapping(prefix);
198         }
199     }
200
201     /**
202      * Receive notification of the beginning of an element.
203      *
204      * @param uri The Namespace URI, or the empty string if the element has no
205      * Namespace URI or if Namespace
206      * processing is not being performed.
207      * @param loc The local name (without prefix), or the empty string if
208      * Namespace processing is not being performed.
209      * @param raw The raw XML 1.0 name (with prefix), or the empty string if
210      * raw names are not available.
211      * @param a The attributes attached to the element. If there are no
212      * attributes, it shall be an empty Attributes object.
213      */

214     public void startElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw, Attributes JavaDoc a)
215     throws SAXException JavaDoc {
216         if (uri == null) uri = "";
217         if (this.extractURI.equals(uri) && this.extractElement.equals(loc)) {
218             extractLevel++;
219             fragmentID++;
220             if (getLogger().isDebugEnabled()) {
221                 getLogger().debug("extractLevel now " + extractLevel + ".");
222             }
223
224             try {
225                 this.serializer = (XMLSerializer) this.manager.lookup(XMLSerializer.ROLE);
226             } catch (ServiceException se) {
227                 throw new SAXException JavaDoc("Could not lookup for XMLSerializer.", se);
228             }
229
230             // Start the DOM document
231
this.serializer.startDocument();
232
233             Iterator JavaDoc itt = prefixMap.entrySet().iterator();
234             while (itt.hasNext()) {
235                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc)itt.next();
236                 this.serializer.startPrefixMapping(
237                     (String JavaDoc)entry.getKey(),
238                     (String JavaDoc)entry.getValue()
239                 );
240             }
241         }
242
243         if (extractLevel == 0) {
244             super.startElement(uri, loc, raw, a);
245         } else {
246             this.serializer.startElement(uri, loc, raw, a);
247         }
248     }
249
250
251     /**
252      * Receive notification of the end of an element.
253      *
254      * @param uri The Namespace URI, or the empty string if the element has no
255      * Namespace URI or if Namespace
256      * processing is not being performed.
257      * @param loc The local name (without prefix), or the empty string if
258      * Namespace processing is not being performed.
259      * @param raw The raw XML 1.0 name (with prefix), or the empty string if
260      * raw names are not available.
261      */

262     public void endElement(String JavaDoc uri, String JavaDoc loc, String JavaDoc raw)
263     throws SAXException JavaDoc {
264         if (extractLevel == 0) {
265             super.endElement(uri, loc, raw);
266         } else {
267             this.serializer.endElement(uri, loc, raw);
268             if (uri == null) uri = "";
269             if (this.extractURI.equals(uri) && this.extractElement.equals(loc)) {
270                 extractLevel--;
271                 if (getLogger().isDebugEnabled()) {
272                     getLogger().debug("extractLevel now " + extractLevel + ".");
273                 }
274
275                 if (extractLevel == 0) {
276                     // finish building the fragment. remove existing prefix mappings.
277
Iterator JavaDoc itt = prefixMap.entrySet().iterator();
278                     while (itt.hasNext()) {
279                         Map.Entry JavaDoc entry = (Map.Entry JavaDoc) itt.next();
280                         this.serializer.endPrefixMapping(
281                             (String JavaDoc)entry.getKey()
282                         );
283                     }
284                     this.serializer.endDocument();
285
286                     Store store = null;
287                     String JavaDoc id = Long.toHexString((hashCode()^HashUtil.hash(requestURI)) + fragmentID);
288                     try {
289                         store = (Store) this.manager.lookup(Store.TRANSIENT_STORE);
290                         store.store(id, this.serializer.getSAXFragment());
291                     } catch (ServiceException se) {
292                         throw new SAXException JavaDoc("Could not lookup for transient store.", se);
293                     } catch (IOException JavaDoc ioe) {
294                         throw new SAXException JavaDoc("Could not store fragment.", ioe);
295                     } finally {
296                         this.manager.release(store);
297                         this.manager.release(this.serializer);
298                         this.serializer = null;
299                     }
300
301                     if (getLogger().isDebugEnabled()) {
302                         getLogger().debug("Stored document " + id + ".");
303                     }
304
305                     // Insert ref.
306
super.startPrefixMapping("fe", FE_URI);
307                     AttributesImpl JavaDoc atts = new AttributesImpl JavaDoc();
308                     atts.addAttribute("", "fragment-id", "fragment-id", "CDATA", id);
309                     super.startElement(FE_URI, "fragment", "fe:fragment", atts);
310                     super.endElement(FE_URI, "fragment", "fe:fragment");
311                     super.endPrefixMapping("fe");
312                 }
313             }
314         }
315     }
316
317     /**
318      * Receive notification of character data.
319      *
320      * @param c The characters from the XML document.
321      * @param start The start position in the array.
322      * @param len The number of characters to read from the array.
323      */

324     public void characters(char c[], int start, int len)
325     throws SAXException JavaDoc {
326         if (extractLevel == 0) {
327             super.characters(c, start, len);
328         } else {
329             this.serializer.characters(c, start, len);
330         }
331     }
332
333     /**
334      * Receive notification of ignorable whitespace in element content.
335      *
336      * @param c The characters from the XML document.
337      * @param start The start position in the array.
338      * @param len The number of characters to read from the array.
339      */

340     public void ignorableWhitespace(char c[], int start, int len)
341     throws SAXException JavaDoc {
342         if (extractLevel == 0) {
343             super.ignorableWhitespace(c, start, len);
344         } else {
345             this.serializer.ignorableWhitespace(c, start, len);
346         }
347     }
348
349     /**
350      * Receive notification of a processing instruction.
351      *
352      * @param target The processing instruction target.
353      * @param data The processing instruction data, or null if none was
354      * supplied.
355      */

356     public void processingInstruction(String JavaDoc target, String JavaDoc data)
357     throws SAXException JavaDoc {
358         if (extractLevel == 0) {
359             super.processingInstruction(target, data);
360         } else {
361             this.serializer.processingInstruction(target, data);
362         }
363     }
364
365     /**
366      * Receive notification of a skipped entity.
367      *
368      * @param name The name of the skipped entity. If it is a parameter
369      * entity, the name will begin with '%'.
370      */

371     public void skippedEntity(String JavaDoc name)
372     throws SAXException JavaDoc {
373         if (extractLevel == 0) {
374             super.skippedEntity(name);
375         } else {
376             this.serializer.skippedEntity(name);
377         }
378     }
379
380     /**
381      * Report the start of DTD declarations, if any.
382      *
383      * @param name The document type name.
384      * @param publicId The declared public identifier for the external DTD
385      * subset, or null if none was declared.
386      * @param systemId The declared system identifier for the external DTD
387      * subset, or null if none was declared.
388      */

389     public void startDTD(String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId)
390     throws SAXException JavaDoc {
391         if (extractLevel == 0) {
392             super.startDTD(name, publicId, systemId);
393         } else {
394             throw new SAXException JavaDoc(
395                 "Recieved startDTD after beginning fragment extraction process."
396             );
397         }
398     }
399
400     /**
401      * Report the end of DTD declarations.
402      */

403     public void endDTD()
404     throws SAXException JavaDoc {
405         if (extractLevel == 0) {
406             super.endDTD();
407         } else {
408             throw new SAXException JavaDoc(
409                 "Recieved endDTD after beginning fragment extraction process."
410             );
411         }
412     }
413
414     /**
415      * Report the beginning of an entity.
416      *
417      * @param name The name of the entity. If it is a parameter entity, the
418      * name will begin with '%'.
419      */

420     public void startEntity(String JavaDoc name)
421     throws SAXException JavaDoc {
422         if (extractLevel == 0) {
423             super.startEntity(name);
424         } else {
425             this.serializer.startEntity(name);
426         }
427     }
428
429     /**
430      * Report the end of an entity.
431      *
432      * @param name The name of the entity that is ending.
433      */

434     public void endEntity(String JavaDoc name)
435     throws SAXException JavaDoc {
436         if (extractLevel == 0) {
437             super.endEntity(name);
438         } else {
439             this.serializer.endEntity(name);
440         }
441     }
442
443     /**
444      * Report the start of a CDATA section.
445      */

446     public void startCDATA()
447     throws SAXException JavaDoc {
448         if (extractLevel == 0) {
449             super.startCDATA();
450         } else {
451             this.serializer.startCDATA();
452         }
453     }
454
455     /**
456      * Report the end of a CDATA section.
457      */

458     public void endCDATA()
459     throws SAXException JavaDoc {
460         if (extractLevel == 0) {
461             super.endCDATA();
462         } else {
463             this.serializer.endCDATA();
464         }
465     }
466
467     /**
468      * Report an XML comment anywhere in the document.
469      *
470      * @param ch An array holding the characters in the comment.
471      * @param start The starting position in the array.
472      * @param len The number of characters to use from the array.
473      */

474     public void comment(char ch[], int start, int len)
475     throws SAXException JavaDoc {
476         if (extractLevel == 0) {
477             super.comment(ch, start, len);
478         } else {
479             this.serializer.comment(ch, start, len);
480         }
481     }
482 }
483
Popular Tags