KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > exoplatform > services > jcr > impl > core > TicketImpl


1 /***************************************************************************
2  * Copyright 2001-2003 The eXo Platform SARL All rights reserved. *
3  * Please look at license.txt in info directory for more license detail. *
4  **************************************************************************/

5
6 package org.exoplatform.services.jcr.impl.core;
7
8 import java.io.ByteArrayInputStream JavaDoc;
9 import java.io.IOException JavaDoc;
10 import java.io.InputStream JavaDoc;
11 import java.util.ArrayList JavaDoc;
12 import java.util.Collection JavaDoc;
13 import java.util.HashMap JavaDoc;
14 import java.util.LinkedList JavaDoc;
15 import java.util.Map JavaDoc;
16
17 import javax.jcr.ActionVetoedException;
18 import javax.jcr.Credentials;
19 import javax.jcr.InvalidSerializedDataException;
20 import javax.jcr.ItemExistsException;
21 import javax.jcr.ItemNotFoundException;
22 import javax.jcr.LoginException;
23 import javax.jcr.NamespaceException;
24 import javax.jcr.Node;
25 import javax.jcr.PathNotFoundException;
26 import javax.jcr.Repository;
27 import javax.jcr.RepositoryException;
28 import javax.jcr.SimpleCredentials;
29 import javax.jcr.Ticket;
30 import javax.jcr.Workspace;
31 import javax.jcr.access.AccessDeniedException;
32 import javax.jcr.nodetype.ConstraintViolationException;
33
34 import org.exoplatform.container.PortalContainer;
35 import org.exoplatform.services.jcr.core.WorkspaceRegistry;
36 import org.exoplatform.services.jcr.impl.util.DocNodeImporter;
37 import org.exoplatform.services.jcr.impl.util.NodeTypeRecognizer;
38 import org.exoplatform.services.jcr.impl.util.SysNodeImporter;
39 import org.exoplatform.services.jcr.storage.WorkspaceContainer;
40 import org.xml.sax.ContentHandler JavaDoc;
41 import org.xml.sax.SAXException JavaDoc;
42
43 /**
44  * Created by The eXo Platform SARL .
45  * <p/>
46  * The ticket represents a kind of key to the repository and
47  * encapsulates the identity of the user and all access-related
48  * restrictions that flow from that identity.
49  * In level 1, access control is beyond the scope of this specification
50  * (thought level 1 repositories may still implement it, of course). The
51  * only requirement is that the identity of the user, and hence their
52  * access privileges are bound to the ticket.
53  *
54  * @author <a HREF="mailto:geaz@users.sourceforge.net">Gennady Azarenkov</a>
55  * @version $Id: TicketImpl.java,v 1.23 2004/09/05 17:14:28 geaz Exp $
56  */

57
58 public class TicketImpl implements Ticket {
59
60   private static final String JavaDoc ANONYMOUS = "anonymous";
61 // private static final String DEFAULT = "default";
62

63   private RepositoryImpl repository;
64   private Credentials credentials;
65   private Workspace workspace;
66   private NodesModificationManager nodesManager;
67   private String JavaDoc workspaceName;
68   private Map JavaDoc namespaces;
69
70
71   public TicketImpl(RepositoryImpl repository, Credentials credentials, String JavaDoc workspaceName)
72     throws RepositoryException {
73
74     WorkspaceRegistry workspaceRepository = (WorkspaceRegistry) PortalContainer.getInstance().
75         getComponentInstanceOfType(WorkspaceRegistry.class);
76     this.repository = repository;
77     this.credentials = credentials;
78     if (credentials == null) {
79       this.credentials = new SimpleCredentials(ANONYMOUS, ANONYMOUS.toCharArray());
80     }
81     this.workspaceName = workspaceName;
82     if (workspaceName == null) {
83         throw new RuntimeException JavaDoc("Workspace name could not be NULL!");
84     }
85     this.workspace = workspaceRepository.getWorkspace(repository.getName(), workspaceName, this);
86     this.nodesManager = new NodesModificationManager(this);
87     namespaces = new HashMap JavaDoc();
88   }
89
90   /**
91    * 6.1.3
92    * Gets the Repository that issued this ticket.
93    */

94   public Repository getRepository() {
95     return repository;
96   }
97
98   /**
99    * 6.1.3
100    * Return the Credentials object that was used to
101    * authorize the issue of this ticket.
102    */

103   public Credentials getCredentials() {
104     return credentials;
105   }
106
107   /**
108    * 6.1.3
109    * Returns a new ticket in accordance with the
110    * specified (new) credentials. In effect allows the
111    * current user to "impersonate" another use
112    * (assuming that their original ticket gives them that
113    * right).
114    */

115   public Ticket impersonate(Credentials c) throws LoginException {
116     try {
117       return new TicketImpl(repository, c, workspaceName);
118     } catch (Exception JavaDoc e) {
119       throw new LoginException(e.getMessage());
120     }
121   }
122
123
124   /**
125    * Returns the <code>Workspace</code> attached to this <code>Ticket</code>.
126    *
127    * @return a <code>{@link Workspace}</code> object.
128    */

129   public Workspace getWorkspace() {
130     return workspace;
131   }
132
133   /**
134    * Returns the root node of the workspace.
135    * The root node, "/", is the main access point to the content of the
136    * workspace.
137    *
138    * @return The root node of the workspace: a <code>Node</code> object.
139    * @throws RepositoryException if an error occurs.
140    */

141   public Node getRootNode() throws RepositoryException {
142     NodeImpl node = (NodeImpl) nodesManager.getNodeByPath("/");
143     if (node != null) {
144       node.setTicket(this);
145     } else
146       throw new RepositoryException("Ticket.getRootNode fatal error! RootNode could not be NULL");
147
148     return node;
149
150   }
151
152   /**
153    * Returns the node specifed by the given UUID. Only applies to nodes that
154    * expose a UUID, in other words, those of mixin node type
155    * <code>mix:referenceable</code>
156    *
157    * @param uuid A universally unique identifier.
158    * @return A <code>Node</code>.
159    * @throws ItemNotFoundException if the specified UUID is not found.
160    * @throws RepositoryException if another error occurs.
161    */

162   public Node getNodeByUUID(String JavaDoc uuid) throws ItemNotFoundException, RepositoryException {
163     NodeImpl node = (NodeImpl) nodesManager.getNodeByUUID(uuid);
164     if (node != null) {
165       node.setTicket(this);
166     } else
167       throw new ItemNotFoundException("Ticket.getNodeByUUID failed. Node with UUID='" + uuid + "' not found.");
168
169     return node;
170   }
171
172   /**
173    * Returns the node at the specified absolute path.
174    *
175    * @param absPath An absolute path.
176    * @return A <code>Node</code>.
177    * @throws PathNotFoundException if the specified path cannot be found.
178    * @throws RepositoryException if another error occurs.
179    */

180   public Node getNodeByAbsPath(String JavaDoc absPath) throws PathNotFoundException, RepositoryException {
181     NodeImpl node = (NodeImpl) nodesManager.getNodeByPath(absPath);
182     if (node != null) {
183       node.setTicket(this);
184     } else
185       throw new PathNotFoundException("Ticket.getNodeByAbsPath failed. Path'" + absPath + "' not found.");
186
187     return node;
188   }
189
190
191   /**
192    * Validates and (if validation succeeds) persists all changes made through
193    * this Ticket since the last <code>save</code> or </code>revert</code>.
194    * <p/>
195    * Constraints mandated by node types are validated on save. If validation
196    * fails a <code>ConstraintViolationException</code> is thrown and the
197    * state of the transient storage is left unaffected. If validation succeeds
198    * then all pending changes are persited and the transient change cache is
199    * flushed.
200    * <p/>
201    * The save method allows a node to be in a temporarily invalid state while
202    * it is being "built", that is, while it is having properties and child
203    * nodes added to it. Once it is in a consistent state it can be saved.
204    * <p/>
205    * An <code>AccessDeniedException</code> will be thrown if an attempt is
206    * made to save changes for which the current user does not have sufficient
207    * access rights.
208    * <p/>
209    * An <code>ActionVetoedException</code> will be thrown if a
210    * <code>VetoableEventListener</code> vetoes one of the changes being saved.
211    * <p/>
212    * If save succeeds then the all changes are removed from the cache
213    * of pending changes in the ticket.
214    *
215    * @throws ConstraintViolationException If any of the changes would
216    * violate a constraint as defined by the node type of the respective node.
217    * @throws AccessDeniedException if the current ticket does not have
218    * sufficient access rights to complete the operation.
219    * @throws RepositoryException If another error occurs.
220    * @throws ActionVetoedException If a VetoableEventListener vetoes one of
221    * the changes being saved.
222    */

223   public void save() throws AccessDeniedException, ConstraintViolationException,
224       ActionVetoedException, RepositoryException {
225     getRootNode().save(false);
226   }
227
228   /**
229    * Discards all pending changes made through this ticket, that is, all
230    * changes made since the last sucessful <code>save</code>.
231    *
232    * @throws RepositoryException If an unexpected error occurs.
233    */

234   public void revert() throws RepositoryException {
235     nodesManager.rollback((NodeImpl) getRootNode());
236   }
237
238   /**
239    * Deserializes an XML document (in <b>system view</b> form or <b>document
240    * view</b> form) and adds the resulting item subtree as a child of the
241    * node at <code>parentAbsPath</code>. Requires a <code>save</code> to
242    * persist the changes.
243    * <p/>
244    * The deserialization mechanism must take into account the
245    * property <code>jcr:uuid</code> in order to reconstruct hard links
246    * across serialization/deserialization cycles.
247    * <p/>
248    * If node type restrictions prevent the addition of the subtree to the
249    * node at <code>parentAbsPath</code>, a <code>ConstraintViolationException</code>
250    * is thrown.
251    * <p/>
252    * If the XML stream provided is not a valid JCR <b>system view</b> XML
253    * document then an <code>InvalidSerializedDataException</code> is thrown.
254    * <p/>
255    * If the user does not have sufficient access rights to write the
256    * deserialized nodes and properties, then an
257    * <code>AccessDeniedException</code> is thrown on <code>save</code>.
258    * <p/>
259    *
260    * @param parentAbsPath the absolute path of the node below which the deserialized
261    * subtree is added.
262    * @param in The <code>Inputstream</code> from which the XML to be deserilaized
263    * is read.
264    * @throws java.io.IOException if an error during an I/O operation occurs.
265    * @throws PathNotFoundException if no node exists at <code>parentAbsPath</code>.
266    * @throws ItemExistsException if an item by the same name as the newly
267    * imported root node already exists.
268    * @throws ConstraintViolationException if node type restrictions prevent
269    * the addition of the subtree to the node at <code>parentAbsPath</code>
270    * @throws InvalidSerializedDataException if the serialized data being input is
271    * not a valid JCR <b>system view</b> XML document.
272    * @throws RepositoryException is another error occurs.
273    */

274   public void importXML(String JavaDoc parentAbsPath, InputStream JavaDoc in) throws IOException JavaDoc, PathNotFoundException,
275       ItemExistsException, ConstraintViolationException, InvalidSerializedDataException, RepositoryException {
276     int type;
277     byte[] buffer = new byte[in.available()];
278     ByteArrayInputStream JavaDoc str;
279     try {
280       in.read(buffer);
281       str = new ByteArrayInputStream JavaDoc(buffer);
282       type = NodeTypeRecognizer.recognize(str);
283     } catch (Exception JavaDoc e) {
284       throw new IOException JavaDoc(e.getMessage());
285     }
286
287     str = new ByteArrayInputStream JavaDoc(buffer);
288     if (type == NodeTypeRecognizer.SYS){
289       importSysView(parentAbsPath, str);
290     } else {
291       importDocView(parentAbsPath, str);
292     }
293   }
294
295   /**
296    * Deserializes the stream of SAX events (from either system view or
297    * document view XML source) defined by the series of calls of
298    * the methods of the <code>org.xml.ContentHandler</code> into a subtree of
299    * items immediately below the node at <code>parentAbsPath</code>. If the
300    * incoming XML stream (in the form of SAX events) is not a valid JCR
301    * system view or document view XML document then the
302    * <code>ContentHandler</code> will throw a <code>SAXException</code> in
303    * one of its methods. After the document has been fed in <code>save</code>
304    * must be called to persist the changes to the repository.
305    *
306    * @param parentAbsPath the absolute path of a node under which (as child) the imported
307    * subtree will be built.
308    * @return an org.xml.ContentHandler whose methods may be called to feed SAX
309    * events into the deserializer.
310    * @throws ItemExistsException if an item alread exists at <code>parentAbsPath</code>.
311    * @throws PathNotFoundException if no node exists at <code>parentPath</code>.
312    * @throws RepositoryException if another error occurs.
313    */

314   public ContentHandler JavaDoc importXML(String JavaDoc parentAbsPath) throws PathNotFoundException, ItemExistsException, RepositoryException {
315     throw new RuntimeException JavaDoc("TODO implement importXML()!");
316   }
317
318   /**
319    * Within the scope of this ticket, rename a persistently registered
320    * namespace URI to the new prefix. The renaming only affects operations
321    * done through this ticket. To clear all renamings the client must acquire
322    * a new ticket.
323    * <p/>
324    * If the specified <code>uri</code> is not among those registered in the
325    * <code>NamespaceRegistry</code> then a <code>NamespaceException</code> is
326    * thrown.
327    *
328    * @param prefix a string
329    * @param uri a string
330    * @throws NamespaceException if specified uri is not registered.
331    */

332   public void setPrefix(String JavaDoc prefix, String JavaDoc uri) throws NamespaceException {
333     try {
334       workspace.getNamespaceRegistry().getPrefix(uri); // throws exception if not found
335
namespaces.put(prefix, uri);
336     } catch (Exception JavaDoc e) {
337       throw new NamespaceException(e.getMessage());
338     }
339   }
340
341   /**
342    * Returns all prefixes currently set for this ticket. This includes all
343    * those registered in the <code>NamespaceRegistry</code> but <i>not
344    * over-ridden</i> by a <code>Ticket.setPrefix</code>, plus those currently set
345    * locally by <code>Ticket.setPrefix</code>.
346    *
347    * @return a string array
348    */

349   public String JavaDoc[] getPrefixes() {
350     Collection JavaDoc allPrefixes = new LinkedList JavaDoc();
351     allPrefixes.addAll(namespaces.keySet());
352     String JavaDoc[] permanentPrefixes = workspace.getNamespaceRegistry().getPrefixes();
353     for (int i = 0; i < permanentPrefixes.length; i++) {
354       String JavaDoc permanentPrefix = permanentPrefixes[i];
355       String JavaDoc uri = null;
356       try {
357         uri = workspace.getNamespaceRegistry().getURI(permanentPrefix);
358         if (!allPrefixes.contains(permanentPrefix) && !(namespaces.values().contains(uri))) {
359           allPrefixes.add(permanentPrefix);
360         }
361       } catch (RepositoryException e) {
362         e.printStackTrace();
363       }
364     }
365     return (String JavaDoc[]) allPrefixes.toArray(new String JavaDoc[allPrefixes.size()]);
366   }
367
368   /**
369    * For a given prefix, returns the URI to which it is mapped as currently
370    * set in this ticket. If the prefix is unknown a NamespaceException is thrown.
371    *
372    * @param prefix a string
373    * @return a string
374    * @throws NamespaceException if the prefix is unknown.
375    */

376   public String JavaDoc getURI(String JavaDoc prefix) throws NamespaceException {
377     String JavaDoc uri = null;
378     try {
379       //look in ticket first
380
uri = (String JavaDoc) namespaces.get(prefix);
381       if (uri != null)
382         return uri;
383       uri = workspace.getNamespaceRegistry().getURI(prefix);
384       if (namespaces.values().contains(uri))
385         return null;
386     } catch (Exception JavaDoc e) {
387       throw new NamespaceException("Can not lookup the URI", e);
388     }
389     if (uri == null)
390       throw new NamespaceException("No such " + uri + " uri in the NamespaceRepository");
391
392     return uri;
393   }
394
395   /**
396    * Releases all resources associate with this ticket. Calling this method
397    * is not mandatory since a good implementaion should automatically timeout
398    * anyway. However, when more precise control over resource allocation is
399    * need this method can be used.
400    */

401   public void logout() {
402   }
403
404
405   private void importSysView(String JavaDoc parentPath, InputStream JavaDoc in) throws PathNotFoundException,
406       InvalidSerializedDataException, ConstraintViolationException, RepositoryException {
407     ArrayList JavaDoc items;
408     try {
409       SysNodeImporter.fillItems(parentPath, in, this);
410     } catch (IOException JavaDoc e) {
411       throw new InvalidSerializedDataException(e.getMessage(),e);
412     } catch (SAXException JavaDoc e) {
413       throw new InvalidSerializedDataException(e.getMessage(),e);
414     }
415   }
416
417   private ContentHandler JavaDoc importSysView(String JavaDoc parentPath)
418       throws InvalidSerializedDataException, ConstraintViolationException {
419     throw new ConstraintViolationException("Does Not implemented temporary!");
420   }
421
422   private void importDocView(String JavaDoc parentPath, InputStream JavaDoc in)
423       throws PathNotFoundException, InvalidSerializedDataException,
424       ConstraintViolationException, RepositoryException {
425     try {
426       NodeImpl node = (NodeImpl) this.getNodeByAbsPath(parentPath);
427       node.setTicket(this);
428       DocNodeImporter.fillNode(node, in, new String JavaDoc[0]);
429     } catch (IOException JavaDoc e) {
430       throw new InvalidSerializedDataException("importDocView failed", e);
431     } catch (SAXException JavaDoc e) {
432       throw new InvalidSerializedDataException("importDocView failed", e);
433     }
434   }
435
436   private ContentHandler JavaDoc importDocView(String JavaDoc parentPath)
437       throws InvalidSerializedDataException, ConstraintViolationException {
438     throw new ConstraintViolationException("Does Not implemented temporary!");
439   }
440
441   NodesModificationManager getNodesManager() {
442     return this.nodesManager;
443   }
444
445   // for tesing
446
public WorkspaceContainer getContainer() throws RepositoryException {
447     return repository.getContainer(workspaceName);
448   }
449
450   public String JavaDoc getWorkspaceName() {
451     return workspaceName;
452   }
453
454 }
455
Popular Tags