1 16 package org.apache.cocoon.jcr.source; 17 18 import java.io.ByteArrayInputStream ; 19 import java.io.ByteArrayOutputStream ; 20 import java.io.IOException ; 21 import java.io.InputStream ; 22 import java.io.OutputStream ; 23 import java.util.ArrayList ; 24 import java.util.Collection ; 25 import java.util.Collections ; 26 import java.util.GregorianCalendar ; 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 49 public class JCRNodeSource implements Source, TraversableSource, ModifiableTraversableSource { 50 51 52 protected String computedURI; 53 54 55 protected final String path; 56 57 58 protected final JCRSourceFactory factory; 59 60 61 protected final Session session; 62 63 64 protected Node node; 65 66 public JCRNodeSource(JCRSourceFactory factory, Session session, String 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 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 getChildPath(String path, String name) { 112 StringBuffer pathBuf = new StringBuffer (path); 113 if (pathBuf.length() > 1) 116 pathBuf.append('/'); 117 pathBuf.append(name); 118 return pathBuf.toString(); 119 } 120 121 127 public Node getNode() { 128 return this.node; 129 } 130 131 136 public String getPath() { 137 return this.path; 138 } 139 140 145 public Session getSession() { 146 return this.session; 147 } 148 149 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 177 182 public boolean exists() { 183 return this.node != null; 184 } 185 186 191 public InputStream getInputStream() throws IOException , 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 e) { 204 throw new SourceException("Error opening stream for '" + this.getURI() + "'", e); 205 } 206 } 207 208 213 public String getURI() { 214 if (this.computedURI == null) { 215 this.computedURI = this.factory.getScheme() + ":/" + this.path; 216 } 217 return this.computedURI; 218 } 219 220 225 public String getScheme() { 226 return this.factory.getScheme(); 227 } 228 229 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 251 public void refresh() { 252 } 254 255 260 public String 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 value = prop.getString(); 270 return value.length() == 0 ? null : value; 271 } 272 } catch (RepositoryException re) { 273 return null; 274 } 275 } 276 277 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 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 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 getChildren() throws SourceException { 327 if (!isCollection()) { 328 return Collections.EMPTY_LIST; 329 } else { 330 ArrayList children = new ArrayList (); 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 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 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 return null; 362 } 363 364 int lastPos = this.path.lastIndexOf('/'); 365 String parentPath = lastPos == 0 ? "/" : this.path.substring(0, lastPos); 366 return this.factory.createSource(this.session, parentPath); 367 } 368 369 373 public OutputStream getOutputStream() throws IOException { 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 parent.makeCollection(); 385 386 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 os) { 412 if (os instanceof JCRSourceOutputStream) { 413 return ((JCRSourceOutputStream) os).canCancel(); 414 } else { 415 return false; 416 } 417 } 418 419 public void cancel(OutputStream os) throws IOException { 420 if (canCancel(os)) { 421 ((JCRSourceOutputStream) os).cancel(); 422 } else { 423 throw new IllegalArgumentException ("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 JCRNodeSource parent = (JCRNodeSource) getParent(); 436 if (parent == null) { 437 throw new RuntimeException ("Problem: root node does not exist!!"); 438 } 439 parent.makeCollection(); 440 Node parentNode = parent.node; 441 442 String 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 457 461 private class JCRSourceOutputStream extends ByteArrayOutputStream { 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 { 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 (this.toByteArray())); 477 if (info.lastModifiedProp != null) { 478 contentNode.setProperty(info.lastModifiedProp, new GregorianCalendar ()); 479 } 480 if (info.mimeTypeProp != null) { 481 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 { 497 if (isClosed) { 498 throw new IllegalStateException ("Cannot cancel : outputstrem is already closed"); 499 } 500 } 501 } 502 } 503 | Popular Tags |