KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > jcr > source > JCRNodeSource


1 /*
2  * Copyright 2005 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.jcr.source;
17
18 import java.io.ByteArrayInputStream JavaDoc;
19 import java.io.ByteArrayOutputStream JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.InputStream JavaDoc;
22 import java.io.OutputStream JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.GregorianCalendar JavaDoc;
27
28 import javax.jcr.Item;
29 import javax.jcr.Node;
30 import javax.jcr.NodeIterator;
31 import javax.jcr.PathNotFoundException;
32 import javax.jcr.Property;
33 import javax.jcr.RepositoryException;
34 import javax.jcr.Session;
35
36 import org.apache.cocoon.CascadingIOException;
37 import org.apache.excalibur.source.ModifiableTraversableSource;
38 import org.apache.excalibur.source.Source;
39 import org.apache.excalibur.source.SourceException;
40 import org.apache.excalibur.source.SourceNotFoundException;
41 import org.apache.excalibur.source.SourceValidity;
42 import org.apache.excalibur.source.TraversableSource;
43
44 /**
45  * A Source for a JCR node.
46  *
47  * @version $Id: JCRNodeSource.java 292639 2005-09-30 05:59:24Z antonio $
48  */

49 public class JCRNodeSource implements Source, TraversableSource, ModifiableTraversableSource {
50
51     /** The full URI */
52     protected String JavaDoc computedURI;
53
54     /** The node path */
55     protected final String JavaDoc path;
56
57     /** The factory that created this Source */
58     protected final JCRSourceFactory factory;
59
60     /** The session this source is bound to */
61     protected final Session session;
62
63     /** The node pointed to by this source (can be null) */
64     protected Node node;
65
66     public JCRNodeSource(JCRSourceFactory factory, Session session, String JavaDoc path) throws SourceException {
67         this.factory = factory;
68         this.session = session;
69         this.path = path;
70
71         try {
72             Item item = session.getItem(path);
73             if (!item.isNode()) {
74                 throw new SourceException("Path '" + path + "' is a property (should be a node)");
75             } else {
76                 this.node = (Node) item;
77             }
78         } catch (PathNotFoundException e) {
79             // Not found
80
this.node = null;
81         } catch (RepositoryException e) {
82             throw new SourceException("Cannot lookup repository path " + path, e);
83         }
84     }
85
86     public JCRNodeSource(JCRSourceFactory factory, Node node) throws SourceException {
87         this.factory = factory;
88         this.node = node;
89
90         try {
91           this.session = node.getSession();
92           this.path = node.getPath();
93         } catch (RepositoryException e) {
94             throw new SourceException("Cannot get node's informations", e);
95         }
96     }
97
98     public JCRNodeSource(JCRNodeSource parent, Node node) throws SourceException {
99         this.factory = parent.factory;
100         this.session = parent.session;
101         this.node = node;
102
103         try {
104             this.path = getChildPath(parent.path, node.getName());
105
106         } catch (RepositoryException e) {
107             throw new SourceException("Cannot get name of child of " + parent.getURI(), e);
108         }
109     }
110
111     private String JavaDoc getChildPath(String JavaDoc path, String JavaDoc name) {
112         StringBuffer JavaDoc pathBuf = new StringBuffer JavaDoc(path);
113         // Append '/' only if the parent isn't the root (it's path is "/" in
114
// that case)
115
if (pathBuf.length() > 1)
116             pathBuf.append('/');
117         pathBuf.append(name);
118         return pathBuf.toString();
119     }
120
121     /**
122      * Returns the JCR <code>Node</code> this source points to, or
123      * <code>null</code> if it denotes a non-existing path.
124      *
125      * @return the JCR node.
126      */

127     public Node getNode() {
128         return this.node;
129     }
130
131     /**
132      * Returns the path within the repository this source points to.
133      *
134      * @return the path
135      */

136     public String JavaDoc getPath() {
137         return this.path;
138     }
139
140     /**
141      * Returns the JCR <code>Session</code> used by this source.
142      *
143      * @return the JCR session.
144      */

145     public Session getSession() {
146         return this.session;
147     }
148
149     /**
150      * Returns the JCR <code>Node</code> used to store the content of this
151      * source.
152      *
153      * @return the JCR content node, or <code>null</code> if no such node
154      * exist, either because the source is a collection or doesn't
155      * currently contain data.
156      */

157     public Node getContentNode() {
158         if (this.node == null) {
159             return null;
160         }
161
162         if (isCollection()) {
163             return null;
164         }
165
166         try {
167             return this.factory.getContentNode(this.node);
168         } catch (RepositoryException e) {
169             return null;
170         }
171     }
172
173     // =============================================================================================
174
// Source interface
175
// =============================================================================================
176

177     /*
178      * (non-Javadoc)
179      *
180      * @see org.apache.excalibur.source.Source#exists()
181      */

182     public boolean exists() {
183         return this.node != null;
184     }
185
186     /*
187      * (non-Javadoc)
188      *
189      * @see org.apache.excalibur.source.Source#getInputStream()
190      */

191     public InputStream JavaDoc getInputStream() throws IOException JavaDoc, SourceNotFoundException {
192         if (this.node == null) {
193             throw new SourceNotFoundException("Path '" + this.getURI() + "' does not exist");
194         }
195
196         if (this.isCollection()) {
197             throw new SourceException("Path '" + this.getURI() + "' is a collection");
198         }
199
200         try {
201             Property contentProp = this.factory.getContentProperty(this.node);
202             return contentProp.getStream();
203         } catch (Exception JavaDoc e) {
204             throw new SourceException("Error opening stream for '" + this.getURI() + "'", e);
205         }
206     }
207
208     /*
209      * (non-Javadoc)
210      *
211      * @see org.apache.excalibur.source.Source#getURI()
212      */

213     public String JavaDoc getURI() {
214         if (this.computedURI == null) {
215             this.computedURI = this.factory.getScheme() + ":/" + this.path;
216         }
217         return this.computedURI;
218     }
219
220     /*
221      * (non-Javadoc)
222      *
223      * @see org.apache.excalibur.source.Source#getScheme()
224      */

225     public String JavaDoc getScheme() {
226         return this.factory.getScheme();
227     }
228
229     /*
230      * (non-Javadoc)
231      *
232      * @see org.apache.excalibur.source.Source#getValidity()
233      */

234     public SourceValidity getValidity() {
235         if (!exists()) {
236             return null;
237         }
238         try {
239             Property prop = this.factory.getValidityProperty(this.node);
240             return prop == null ? null : new JCRNodeSourceValidity(prop.getValue());
241         } catch (RepositoryException re) {
242             return null;
243         }
244     }
245
246     /*
247      * (non-Javadoc)
248      *
249      * @see org.apache.excalibur.source.Source#refresh()
250      */

251     public void refresh() {
252         // nothing to do here
253
}
254
255     /*
256      * (non-Javadoc)
257      *
258      * @see org.apache.excalibur.source.Source#getMimeType()
259      */

260     public String JavaDoc getMimeType() {
261         if (!exists()) {
262             return null;
263         }
264         try {
265             Property prop = this.factory.getMimeTypeProperty(this.node);
266             if (prop == null) {
267                 return null;
268             } else {
269                 String JavaDoc value = prop.getString();
270                 return value.length() == 0 ? null : value;
271             }
272         } catch (RepositoryException re) {
273             return null;
274         }
275     }
276
277     /*
278      * (non-Javadoc)
279      *
280      * @see org.apache.excalibur.source.Source#getContentLength()
281      */

282     public long getContentLength() {
283         if (!exists()) {
284             return -1;
285         }
286         try {
287             Property prop = this.factory.getContentProperty(this.node);
288             return prop == null ? -1 : prop.getLength();
289         } catch (RepositoryException re) {
290             return -1;
291         }
292     }
293
294     /*
295      * (non-Javadoc)
296      *
297      * @see org.apache.excalibur.source.Source#getLastModified()
298      */

299     public long getLastModified() {
300         if (!exists()) {
301             return 0;
302         }
303         try {
304             Property prop = this.factory.getLastModifiedDateProperty(this.node);
305             return prop == null ? 0 : prop.getDate().getTime().getTime();
306         } catch (RepositoryException re) {
307             return 0;
308         }
309     }
310
311     // =============================================================================================
312
// TraversableSource interface
313
// =============================================================================================
314

315     public boolean isCollection() {
316         if (!exists())
317             return false;
318
319         try {
320             return this.factory.isCollection(this.node);
321         } catch (RepositoryException e) {
322             return false;
323         }
324     }
325
326     public Collection JavaDoc getChildren() throws SourceException {
327         if (!isCollection()) {
328             return Collections.EMPTY_LIST;
329         } else {
330             ArrayList JavaDoc children = new ArrayList JavaDoc();
331
332             NodeIterator nodes;
333             try {
334                 nodes = this.node.getNodes();
335             } catch (RepositoryException e) {
336                 throw new SourceException("Cannot get child nodes for " + getURI(), e);
337             }
338
339             while (nodes.hasNext()) {
340                 children.add(this.factory.createSource(this, nodes.nextNode()));
341             }
342             return children;
343         }
344     }
345
346     public Source getChild(String JavaDoc name) throws SourceException {
347         if (this.isCollection()) {
348             return this.factory.createSource(this.session, getChildPath(this.path, name));
349         } else {
350             throw new SourceException("Not a collection: " + getURI());
351         }
352     }
353
354     public String JavaDoc getName() {
355         return this.path.substring(this.path.lastIndexOf('/') + 1);
356     }
357
358     public Source getParent() throws SourceException {
359         if (this.path.length() == 1) {
360             // Root
361
return null;
362         }
363
364         int lastPos = this.path.lastIndexOf('/');
365         String JavaDoc parentPath = lastPos == 0 ? "/" : this.path.substring(0, lastPos);
366         return this.factory.createSource(this.session, parentPath);
367     }
368
369     // =============================================================================================
370
// ModifiableTraversableSource interface
371
// =============================================================================================
372

373     public OutputStream JavaDoc getOutputStream() throws IOException JavaDoc {
374         if (isCollection()) {
375             throw new SourceException("Cannot write to collection " + this.getURI());
376         }
377
378         try {
379             Node contentNode;
380             if (!exists()) {
381                 JCRNodeSource parent = (JCRNodeSource) getParent();
382
383                 // Create the path if it doesn't exist
384
parent.makeCollection();
385
386                 // Create our node
387
this.node = this.factory.createFileNode(parent.node, getName());
388                 contentNode = this.factory.createContentNode(this.node);
389             } else {
390                 contentNode = this.factory.getContentNode(this.node);
391             }
392
393             return new JCRSourceOutputStream(contentNode);
394         } catch (RepositoryException e) {
395             throw new SourceException("Cannot create content node for " + getURI(), e);
396         }
397     }
398
399     public void delete() throws SourceException {
400         if (exists()) {
401             try {
402                 this.node.remove();
403                 this.node = null;
404                 this.session.save();
405             } catch (RepositoryException e) {
406                 throw new SourceException("Cannot delete " + getURI(), e);
407             }
408         }
409     }
410
411     public boolean canCancel(OutputStream JavaDoc os) {
412         if (os instanceof JCRSourceOutputStream) {
413             return ((JCRSourceOutputStream) os).canCancel();
414         } else {
415             return false;
416         }
417     }
418
419     public void cancel(OutputStream JavaDoc os) throws IOException JavaDoc {
420         if (canCancel(os)) {
421             ((JCRSourceOutputStream) os).cancel();
422         } else {
423             throw new IllegalArgumentException JavaDoc("Stream cannot be cancelled");
424         }
425     }
426
427     public void makeCollection() throws SourceException {
428         if (exists()) {
429             if (!isCollection()) {
430                 throw new SourceException("Cannot make a collection with existing node at " + getURI());
431             }
432         } else {
433             try {
434                 // Ensure parent exists
435
JCRNodeSource parent = (JCRNodeSource) getParent();
436                 if (parent == null) {
437                     throw new RuntimeException JavaDoc("Problem: root node does not exist!!");
438                 }
439                 parent.makeCollection();
440                 Node parentNode = parent.node;
441
442                 String JavaDoc typeName = this.factory.getFolderNodeType(parentNode);
443
444                 this.node = parentNode.addNode(getName(), typeName);
445                 this.session.save();
446
447             } catch (RepositoryException e) {
448                 throw new SourceException("Cannot make collection " + this.getURI(), e);
449             }
450         }
451     }
452
453     // ----------------------------------------------------------------------------------
454
// Private helper class for ModifiableSource implementation
455
// ----------------------------------------------------------------------------------
456

457     /**
458      * An outputStream that will save the session upon close, and discard it
459      * upon cancel.
460      */

461     private class JCRSourceOutputStream extends ByteArrayOutputStream JavaDoc {
462         private boolean isClosed = false;
463
464         private final Node contentNode;
465
466         public JCRSourceOutputStream(Node contentNode) {
467             this.contentNode = contentNode;
468         }
469
470         public void close() throws IOException JavaDoc {
471             if (!isClosed) {
472                 super.close();
473                 this.isClosed = true;
474                 try {
475                     JCRSourceFactory.ContentTypeInfo info = (JCRSourceFactory.ContentTypeInfo) factory.getTypeInfo(contentNode);
476                     contentNode.setProperty(info.contentProp, new ByteArrayInputStream JavaDoc(this.toByteArray()));
477                     if (info.lastModifiedProp != null) {
478                         contentNode.setProperty(info.lastModifiedProp, new GregorianCalendar JavaDoc());
479                     }
480                     if (info.mimeTypeProp != null) {
481                         // FIXME: define mime type
482
contentNode.setProperty(info.mimeTypeProp, "");
483                     }
484
485                     JCRNodeSource.this.session.save();
486                 } catch (RepositoryException e) {
487                     throw new CascadingIOException("Cannot save content to " + getURI(), e);
488                 }
489             }
490         }
491
492         public boolean canCancel() {
493             return !isClosed;
494         }
495
496         public void cancel() throws IOException JavaDoc {
497             if (isClosed) {
498                 throw new IllegalStateException JavaDoc("Cannot cancel : outputstrem is already closed");
499             }
500         }
501     }
502 }
503
Popular Tags