KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > source > impl > XModuleSource


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.components.source.impl;
17
18
19 import java.io.InputStream JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.OutputStream JavaDoc;
22 import java.io.ByteArrayOutputStream JavaDoc;
23 import java.io.ByteArrayInputStream JavaDoc;
24 import java.net.MalformedURLException JavaDoc;
25 import java.util.Map JavaDoc;
26
27 import org.apache.avalon.framework.configuration.ConfigurationException;
28 import org.apache.avalon.framework.logger.Logger;
29 import org.apache.avalon.framework.service.ServiceException;
30 import org.apache.avalon.framework.service.ServiceManager;
31 import org.apache.avalon.framework.service.ServiceSelector;
32
33 import org.apache.excalibur.source.ModifiableSource;
34 import org.apache.excalibur.source.SourceException;
35 import org.apache.excalibur.source.impl.AbstractSource;
36 import org.apache.excalibur.xml.sax.SAXParser;
37 import org.apache.excalibur.xml.sax.XMLizable;
38
39 import org.apache.cocoon.components.modules.input.InputModule;
40 import org.apache.cocoon.components.modules.output.OutputModule;
41 import org.apache.cocoon.serialization.XMLSerializer;
42 import org.apache.cocoon.util.jxpath.DOMFactory;
43 import org.apache.cocoon.xml.dom.DOMBuilder;
44 import org.apache.cocoon.xml.dom.DOMStreamer;
45
46 import org.apache.commons.jxpath.JXPathContext;
47
48 import org.w3c.dom.Document JavaDoc;
49 import org.w3c.dom.Node JavaDoc;
50
51 import org.xml.sax.ContentHandler JavaDoc;
52 import org.xml.sax.InputSource JavaDoc;
53 import org.xml.sax.SAXException JavaDoc;
54
55 /**
56  * A <code>ModifiableSource</code> that takes its content from a
57  * module.
58  * <p>The URI syntax is
59  * "xmodule:[<input-module>|<output-module>]:attribute-name[#XPath]",
60  * where :
61  * <ul>
62  * <li>an input-module name is used for finding an input-module for reading data from</li>,
63  * <li>an output-module name is used for finding an output-module for writing data to</li>,
64  * <li>"attribute-name" is the name of the attribute found in the module</li>,
65  * <li>"XPath" is an XPath that is aplied on the object in the
66  * attribute, by using JXPath.</li>
67  * </ul>
68  * </p>
69  *
70  * @author <a HREF="mailto:danielf@nada.kth.se">Daniel Fagerstom</a>
71  */

72
73 public class XModuleSource
74     extends AbstractSource
75     implements ModifiableSource, XMLizable, DOMBuilder.Listener {
76
77     private final static String JavaDoc SCHEME = "xmodule";
78     private String JavaDoc attributeType;
79     private String JavaDoc attributeName;
80     private String JavaDoc xPath;
81     private ServiceManager manager;
82     private Map JavaDoc objectModel;
83     private Logger logger;
84     
85     /**
86      * Create a xmodule source from a 'xmodule:' uri and a the object model.
87      * <p>The uri is of the form "xmodule:/attribute-type/attribute-name/xpath</p>
88      */

89     public XModuleSource( Map JavaDoc objectModel, String JavaDoc uri,
90                           ServiceManager manager, Logger logger )
91         throws MalformedURLException JavaDoc {
92
93         this.objectModel = objectModel;
94         this.manager = manager;
95         this.logger = logger;
96
97         setSystemId( uri );
98
99         // Scheme
100
int start = 0;
101         int end = uri.indexOf( ':' );
102         if ( end == -1 )
103             throw new MalformedURLException JavaDoc("Malformed uri for xmodule source (cannot find scheme) : " + uri);
104
105         String JavaDoc scheme = uri.substring( start, end );
106         if ( !SCHEME.equals( scheme ) )
107             throw new MalformedURLException JavaDoc("Malformed uri for a xmodule source : " + uri);
108
109         setScheme( scheme );
110
111         // Attribute type
112
start = end + 1;
113         end = uri.indexOf( ':', start );
114         if ( end == -1 ) {
115             throw new MalformedURLException JavaDoc("Malformed uri for xmodule source (cannot find attribute type) : " + uri);
116         }
117         this.attributeType = uri.substring( start, end );
118
119         // Attribute name
120
start = end + 1;
121         end = uri.indexOf( '#', start );
122
123         if ( end == -1 )
124             end = uri.length();
125
126         if ( end == start )
127             throw new MalformedURLException JavaDoc("Malformed uri for xmodule source (cannot find attribute name) : " + uri);
128
129         this.attributeName = uri.substring( start, end );
130
131         // xpath
132
start = end + 1;
133         this.xPath = start < uri.length() ? uri.substring( start ) : "";
134     }
135     
136     /**
137      * Implement this method to obtain SAX events.
138      *
139      */

140
141     public void toSAX(ContentHandler JavaDoc handler)
142         throws SAXException JavaDoc {
143
144         Object JavaDoc obj = getInputAttribute( this.attributeType, this.attributeName );
145         if ( obj == null )
146             throw new SAXException JavaDoc( " The attribute: " + this.attributeName +
147                                     " is empty" );
148
149         if ( !(this.xPath.length() == 0 || this.xPath.equals( "/" )) ) {
150             JXPathContext context = JXPathContext.newContext( obj );
151
152             obj = context.getPointer( this.xPath ).getNode();
153
154             if ( obj == null )
155                 throw new SAXException JavaDoc( "the xpath: " + this.xPath +
156                                         " applied on the attribute: " +
157                                         this.attributeName +
158                                         " returns null");
159         }
160
161         if ( obj instanceof Document JavaDoc ) {
162             DOMStreamer domStreamer = new DOMStreamer( handler );
163             domStreamer.stream( (Document JavaDoc)obj );
164         } else if ( obj instanceof Node JavaDoc ) {
165             DOMStreamer domStreamer = new DOMStreamer( handler );
166             handler.startDocument();
167             domStreamer.stream( (Node JavaDoc)obj );
168             handler.endDocument();
169         } else if ( obj instanceof XMLizable ) {
170             ((XMLizable)obj).toSAX( handler );
171         } else {
172             throw new SAXException JavaDoc( "The object type: " + obj.getClass() +
173                                     " could not be serialized to XML: " + obj );
174         }
175     }
176
177     /**
178      * Return an <code>InputStream</code> object to read from the source.
179      *
180      * @throws IOException if I/O error occured.
181      */

182     // Stolen from QDoxSource
183
public InputStream JavaDoc getInputStream() throws IOException JavaDoc, SourceException {
184         if ( this.logger.isDebugEnabled() ) {
185             this.logger.debug( "Getting InputStream for " + getURI() );
186         }
187
188         // Serialize the SAX events to the XMLSerializer:
189

190         XMLSerializer serializer = new XMLSerializer();
191         ByteArrayInputStream JavaDoc inputStream = null;
192
193         try {
194             ByteArrayOutputStream JavaDoc outputStream = new ByteArrayOutputStream JavaDoc( 2048 );
195             serializer.setOutputStream( outputStream );
196             toSAX( serializer );
197             inputStream = new ByteArrayInputStream JavaDoc( outputStream.toByteArray() );
198         } catch ( SAXException JavaDoc se ) {
199             logger.error( "SAX exception!", se );
200             throw new SourceException( "Serializing SAX to a ByteArray failed!", se );
201         }
202
203         return inputStream;
204     }
205
206     /**
207      * Does this source actually exist ?
208      *
209      * @return true if the resource exists.
210      *
211      */

212     public boolean exists() {
213         boolean exists = false;
214         try {
215             exists = getInputAttribute( this.attributeType, this.attributeName ) != null;
216         } catch ( SAXException JavaDoc e ) {
217             exists = false;
218         }
219         return exists;
220     }
221
222     /**
223      * Get an <code>InputStream</code> where raw bytes can be written to.
224      * The signification of these bytes is implementation-dependent and
225      * is not restricted to a serialized XML document.
226      *
227      * @return a stream to write to
228      */

229     public OutputStream JavaDoc getOutputStream() throws IOException JavaDoc {
230         return new DOMOutputStream();
231     }
232
233     /**
234      * Delete the source
235      */

236     public void delete() throws SourceException {
237         if ( !(this.xPath.length() == 0 || this.xPath.equals( "/" )) ) {
238             Object JavaDoc value;
239             try {
240                 value = getInputAttribute( this.attributeType, this.attributeName );
241             } catch ( SAXException JavaDoc e ) {
242                 throw new SourceException( "delete: ", e );
243             }
244             if ( value == null )
245                 throw new SourceException( " The attribute: " + this.attributeName +
246                                            " is empty" );
247
248             JXPathContext context = JXPathContext.newContext( value );
249             context.removeAll( this.xPath );
250         } else {
251             try {
252                 setOutputAttribute( this.attributeType, this.attributeName, null );
253             } catch ( SAXException JavaDoc e ) {
254                 throw new SourceException( "delete: ", e );
255             }
256         }
257     }
258
259     /**
260      * FIXME
261      * delete is an operator in java script, this method is for
262      * testing puposes in java script only
263      */

264     public void deleteTest() throws SourceException {
265         delete();
266     }
267
268     /**
269      * Can the data sent to an <code>OutputStream</code> returned by
270      * {@link #getOutputStream()} be cancelled ?
271      *
272      * @return true if the stream can be cancelled
273      */

274     public boolean canCancel( OutputStream JavaDoc stream ) { return false; }
275
276     /**
277      * Cancel the data sent to an <code>OutputStream</code> returned by
278      * {@link #getOutputStream()}.
279      * <p>
280      * After cancel, the stream should no more be used.
281      */

282     public void cancel(OutputStream JavaDoc stream) throws IOException JavaDoc {}
283
284     /**
285      * Get a <code>ContentHandler</code> where an XML document can
286      * be written using SAX events.
287      * <p>
288      * Care should be taken that the returned handler can actually
289      * be a {@link org.apache.cocoon.xml.XMLConsumer} supporting also
290      * lexical events such as comments.
291      *
292      * @return a handler for SAX events
293      */

294     public ContentHandler JavaDoc getContentHandler() {
295         return new DOMBuilder( this );
296     }
297
298     public void notify( Document JavaDoc insertDoc ) throws SAXException JavaDoc {
299
300         // handle xpaths, we are only handling inserts, i.e. if there is no
301
// attribute of the given name and type the operation will fail
302
if ( !(this.xPath.length() == 0 || this.xPath.equals( "/" )) ) {
303
304             Object JavaDoc value = getInputAttribute( this.attributeType, this.attributeName );
305             if ( value == null )
306                 throw new SAXException JavaDoc( " The attribute: " + this.attributeName +
307                                         " is empty" );
308
309             JXPathContext context = JXPathContext.newContext( value );
310
311             if ( value instanceof Document JavaDoc ) {
312                 // If the attribute contains a dom document we
313
// create the elements in the given xpath if
314
// necesary, import the input document and put it
315
// in the place described by the xpath.
316
Document JavaDoc doc = (Document JavaDoc)value;
317                 
318                 Node JavaDoc importedNode =
319                     doc.importNode( insertDoc.getDocumentElement(), true );
320                 
321                 context.setLenient( true );
322                 context.setFactory( new DOMFactory() );
323                 context.createPathAndSetValue( this.xPath, importedNode );
324             } else {
325                 // Otherwise just try to put a the input document in
326
// the place pointed to by the xpath
327
context.setValue( this.xPath, insertDoc );
328             }
329                     
330         } else {
331             setOutputAttribute( this.attributeType, this.attributeName, insertDoc );
332         }
333     }
334
335     private class DOMOutputStream extends ByteArrayOutputStream JavaDoc {
336         public void close() throws IOException JavaDoc {
337             SAXParser parser = null;
338             try {
339                 parser = (SAXParser)XModuleSource.this.manager.lookup( SAXParser.ROLE );
340
341                 parser.parse( new InputSource JavaDoc( new ByteArrayInputStream JavaDoc( super.toByteArray() ) ),
342                               XModuleSource.this.getContentHandler());
343             } catch (Exception JavaDoc e){
344                 throw new IOException JavaDoc("Exception during processing of " +
345                                        XModuleSource.super.getURI() +
346                                        e.getMessage());
347             } finally {
348                 if (parser != null) XModuleSource.this.manager.release( parser );
349             }
350             super.close();
351         }
352     }
353
354
355     private Object JavaDoc getInputAttribute( String JavaDoc inputModuleName, String JavaDoc attributeName )
356         throws SAXException JavaDoc {
357         Object JavaDoc obj;
358         ServiceSelector selector = null;
359         InputModule inputModule = null;
360         try {
361             selector = (ServiceSelector) this.manager.lookup( InputModule.ROLE + "Selector" );
362             inputModule = (InputModule) selector.select( inputModuleName );
363             obj = inputModule.getAttribute( attributeName, null, this.objectModel );
364
365         } catch ( ServiceException e ) {
366             throw new SAXException JavaDoc( "Could not find an InputModule of the type " +
367                                     inputModuleName , e );
368         } catch ( ConfigurationException e ) {
369             throw new SAXException JavaDoc( "Could not find an attribute: " + attributeName +
370                                     " from the InputModule " + inputModuleName, e );
371         } finally {
372             if ( inputModule != null ) selector.release( inputModule );
373             this.manager.release( selector );
374         }
375
376         return obj;
377     }
378
379     private void setOutputAttribute( String JavaDoc outputModuleName,
380                                      String JavaDoc attributeName, Object JavaDoc value )
381         throws SAXException JavaDoc{
382         ServiceSelector selector = null;
383         OutputModule outputModule = null;
384         try {
385             selector = (ServiceSelector) this.manager.lookup( OutputModule.ROLE + "Selector" );
386             outputModule = (OutputModule) selector.select( outputModuleName );
387             outputModule.setAttribute( null, this.objectModel, attributeName, value );
388             outputModule.commit( null, this.objectModel );
389
390         } catch ( ServiceException e ) {
391             throw new SAXException JavaDoc( "Could not find an OutputModule of the type " +
392                                     outputModuleName , e );
393         } finally {
394             if ( outputModule != null ) selector.release( outputModule );
395             this.manager.release( selector );
396         }
397     }
398 }
399
Popular Tags