View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors.
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   * 
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.graph.connector.base;
25  
26  import java.util.List;
27  import java.util.Set;
28  import java.util.UUID;
29  import net.jcip.annotations.NotThreadSafe;
30  import org.modeshape.graph.ExecutionContext;
31  import org.modeshape.graph.Location;
32  import org.modeshape.graph.connector.LockFailedException;
33  import org.modeshape.graph.connector.UuidAlreadyExistsException;
34  import org.modeshape.graph.property.Name;
35  import org.modeshape.graph.property.Path;
36  import org.modeshape.graph.property.PathNotFoundException;
37  import org.modeshape.graph.property.Property;
38  import org.modeshape.graph.query.QueryResults;
39  import org.modeshape.graph.request.AccessQueryRequest;
40  import org.modeshape.graph.request.FullTextSearchRequest;
41  import org.modeshape.graph.request.InvalidWorkspaceException;
42  import org.modeshape.graph.request.LockBranchRequest.LockScope;
43  
44  /**
45   * A transaction in which all read and write operations against a repository are performed. The actual transaction instance is
46   * obtained by calling {@link Repository#startTransaction(ExecutionContext,boolean)}.
47   * <p>
48   * Note that implementations are not required to be thread-safe, since they (and their corresponding {@link Connection}) are
49   * expected to be used by a single thread.
50   * </p>
51   * 
52   * @param <NodeType> the type of node
53   * @param <WorkspaceType> the type of workspace
54   */
55  @NotThreadSafe
56  public interface Transaction<NodeType extends Node, WorkspaceType extends Workspace> {
57  
58      /**
59       * Get the context in which this operator executes.
60       * 
61       * @return the execution context; never null
62       */
63      ExecutionContext getContext();
64  
65      /**
66       * Get the names of the existing workspaces.
67       * 
68       * @return the immutable set of workspace names; never null
69       */
70      Set<String> getWorkspaceNames();
71  
72      /**
73       * Creates a new workspace with the given name containing only a root node. If the workspace already exists, it is left
74       * untouched and returned.
75       * 
76       * @param name the name of the workspace; may not be null
77       * @param originalToClone the workspace that should be cloned, or null if the new workspace is to only contain a root node
78       * @return the newly created workspace; may not be null
79       * @throws InvalidWorkspaceException if the workspace could not be created
80       */
81      WorkspaceType getWorkspace( String name,
82                                  WorkspaceType originalToClone ) throws InvalidWorkspaceException;
83  
84      /**
85       * Destroy the workspace with the supplied name.
86       * 
87       * @param workspace the workspace that is to be destroyed; may not be null
88       * @return true if the workspace was destroyed, or false if the workspace did not exist
89       * @throws InvalidWorkspaceException if the workspace could not be destroyed
90       */
91      boolean destroyWorkspace( WorkspaceType workspace ) throws InvalidWorkspaceException;
92  
93      /**
94       * Get the root node of the repository workspace.
95       * 
96       * @param workspace the workspace; may not be null
97       * @return the root node; never null
98       */
99      NodeType getRootNode( WorkspaceType workspace );
100 
101     /**
102      * Find the node with the supplied unique identifier.
103      * 
104      * @param workspace the workspace; may not be null
105      * @param location of the node; may not be null
106      * @return the node, or null if there is no node with the supplied identifier
107      * @throws PathNotFoundException if the node at the given location could not be found
108      */
109     NodeType getNode( WorkspaceType workspace,
110                       Location location );
111 
112     /**
113      * Returns the path for the given node with this workspace if one exists, or a {@code null} if no node exists at the given
114      * path.
115      * 
116      * @param workspace the workspace; may not be null
117      * @param node the node for which the path should be retrieved; may not be null
118      * @return the path for the given node with this workspace if one exists or null if the node does not exist in this workspace
119      */
120     Path pathFor( WorkspaceType workspace,
121                   NodeType node );
122 
123     /**
124      * Returns the parent of the supplied node. This method returns null if the supplied node is the root node.
125      * 
126      * @param workspace the workspace; may not be null
127      * @param node the child node; may not be null
128      * @return the parent of this node; or null if the node is the root node for its workspace
129      */
130     NodeType getParent( WorkspaceType workspace,
131                         NodeType node );
132 
133     /**
134      * Find in the supplied parent node the child with the supplied name and same-name-sibling index. This method returns null if
135      * the parent has no such child.
136      * 
137      * @param workspace the workspace; may not be null
138      * @param parent the parent node; may not be null
139      * @param childSegment the segment of the child; may not be null
140      * @return the child of this node; or null if no such child exists
141      */
142     NodeType getChild( WorkspaceType workspace,
143                        NodeType parent,
144                        Path.Segment childSegment );
145 
146     /**
147      * Find in the supplied parent node the first child with the supplied name. This method returns null if the parent has no such
148      * child.
149      * 
150      * @param workspace the workspace; may not be null
151      * @param parent the parent node; may not be null
152      * @param childName the name of the child; may not be null
153      * @return the child of this node; or null if no such child exists
154      */
155     NodeType getFirstChild( WorkspaceType workspace,
156                             NodeType parent,
157                             Name childName );
158 
159     /**
160      * Get the children for the supplied node.
161      * 
162      * @param workspace the workspace; may not be null
163      * @param node the node whose children are to be returned; may not be null
164      * @return the children, never null but possibly empty
165      */
166     List<NodeType> getChildren( WorkspaceType workspace,
167                                 NodeType node );
168 
169     /**
170      * Removes all of the children for this node in a single operation.
171      * 
172      * @param workspace the workspace; may not be null
173      * @param node the node whose children are to be removed; may not be null
174      */
175     void removeAllChildren( WorkspaceType workspace,
176                             NodeType node );
177 
178     /**
179      * Creates a new child node under the supplied parent, where the new child will have the specified name, properties, and
180      * (optionally) UUID. The child will be appended to the list of children, and will be given the appropriate same-name-sibling
181      * index.
182      * 
183      * @param workspace the workspace; may not be null
184      * @param parent the parent node; may not be null
185      * @param name the name; may not be null
186      * @param index index at which the specified child is to be inserted, or -1 if the child is to be appended
187      * @param uuid the UUID of the node, or null if the UUID is to be generated
188      * @param properties the properties for the new node; may be null if there are no other properties
189      * @return the representation of the new node
190      */
191     NodeType addChild( WorkspaceType workspace,
192                        NodeType parent,
193                        Name name,
194                        int index,
195                        UUID uuid,
196                        Iterable<Property> properties );
197 
198     /**
199      * Inserts the specified child at the specified position in the list of children. Shifts the child currently at that position
200      * (if any) and any subsequent children to the right (adds one to their indices). The child is automatically removed from its
201      * existing parent (if it has one), though this method can be used to reorder a child within the same parent.
202      * <p>
203      * This method can also be used to rename an existing child by 'moving' the child node to the existing parent and a new
204      * desired name. However, if no 'beforeOtherChild' is supplied, then the node being renamed will also be moved to the end of
205      * the children.
206      * </p>
207      * 
208      * @param workspace the workspace; may not be null
209      * @param parent the parent node; may not be null
210      * @param newChild the node that is to be added as a child of the parent; may not be null
211      * @param beforeOtherChild the existing child before which the child is to be added; may be null if the child is to be added
212      *        at the end
213      * @param desiredName the desired name for the node; may be null if the new child node's name is to be kept
214      * @return the actual location of the node, or null if the node didn't exist
215      */
216     Location addChild( WorkspaceType workspace,
217                        NodeType parent,
218                        NodeType newChild,
219                        NodeType beforeOtherChild,
220                        Name desiredName );
221 
222     /**
223      * Removes the given node from the repository.
224      * 
225      * @param workspace the workspace; may not be null
226      * @param node the node to be removed; may not be null
227      * @return the actual location of the node, or null if the node didn't exist
228      */
229     Location removeNode( WorkspaceType workspace,
230                          NodeType node );
231 
232     /**
233      * Sets the given properties in a single operation, overwriting any previous properties for the same name. This bulk mutator
234      * should be used when multiple properties are being set in order to allow underlying implementations to optimize their access
235      * to their respective persistent storage mechanism. The implementation should <i>not</i> change the identification
236      * properties.
237      * 
238      * @param workspace the workspace; may not be null
239      * @param node the node; may not be null
240      * @param propertiesToSet the properties to set; may be null or empty if there are no properties being added or set
241      * @param propertiesToRemove the names of the properties that are to be removed; may be null or empty if no properties are
242      *        being removed
243      * @param removeAllExisting true if all existing, non-identification properties should be removed, or false otherwise
244      * @return this map node
245      */
246     NodeType setProperties( WorkspaceType workspace,
247                             NodeType node,
248                             Iterable<Property> propertiesToSet,
249                             Iterable<Name> propertiesToRemove,
250                             boolean removeAllExisting );
251 
252     /**
253      * Removes the property with the given name
254      * 
255      * @param workspace the workspace; may not be null
256      * @param node the node; may not be null
257      * @param propertyName the name of the property to remove; may not be null
258      * @return this map node
259      */
260     NodeType removeProperty( WorkspaceType workspace,
261                              NodeType node,
262                              Name propertyName );
263 
264     /**
265      * This should clone the subgraph given by the original node and place the cloned copy under the supplied new parent. Note
266      * that internal references between nodes within the original subgraph must be reflected as internal nodes within the new
267      * subgraph.
268      * 
269      * @param originalWorkspace the workspace containing the original node that is being cloned; may not be null
270      * @param original the node to be cloned; may not be null
271      * @param newWorkspace the workspace containing the new parent node; may not be null
272      * @param newParent the parent where the clone is to be placed; may not be null
273      * @param desiredName the desired name for the node; if null, the name will be calculated from {@code desiredSegment}; Exactly
274      *        one of {@code desiredSegment} and {@code desiredName} must be non-null
275      * @param desiredSegment the exact segment at which the clone should be rooted; if null, the name will be inferred from
276      *        {@code desiredName}; Exactly one of {@code desiredSegment} and {@code desiredName} must be non-null
277      * @param removeExisting true if existing nodes in the new workspace with the same UUIDs as nodes in the branch rooted at
278      *        {@code original} should be removed; if false, a UuidAlreadyExistsException will be thrown if a UUID conflict is
279      *        detected
280      * @param removedExistingNodes the set into which should be placed all of the existing nodes that were removed as a result of
281      *        this clone operation, or null if these nodes need not be collected
282      * @return the new node, which is the top of the new subgraph
283      * @throws UuidAlreadyExistsException if {@code removeExisting} is true and and a UUID in the source tree already exists in
284      *         the new workspace
285      */
286     NodeType cloneNode( WorkspaceType originalWorkspace,
287                         NodeType original,
288                         WorkspaceType newWorkspace,
289                         NodeType newParent,
290                         Name desiredName,
291                         Path.Segment desiredSegment,
292                         boolean removeExisting,
293                         Set<Location> removedExistingNodes ) throws UuidAlreadyExistsException;
294 
295     /**
296      * This should copy the subgraph given by the original node and place the new copy under the supplied new parent. Note that
297      * internal references between nodes within the original subgraph must be reflected as internal nodes within the new subgraph.
298      * 
299      * @param originalWorkspace the workspace containing the original node that is being cloned; may not be null
300      * @param original the node to be copied; may not be null
301      * @param newWorkspace the workspace containing the new parent node; may not be null
302      * @param newParent the parent where the copy is to be placed; may not be null
303      * @param desiredName the desired name for the node; if null, the name will be obtained from the original node
304      * @param recursive true if the copy should be recursive
305      * @return the new node, which is the top of the new subgraph
306      */
307     NodeType copyNode( WorkspaceType originalWorkspace,
308                        NodeType original,
309                        WorkspaceType newWorkspace,
310                        NodeType newParent,
311                        Name desiredName,
312                        boolean recursive );
313 
314     /**
315      * Perform a query of this workspace.
316      * 
317      * @param workspace the workspace to be searched; may not be null
318      * @param accessQuery the access query; may not be null
319      * @return the query results, or null if the query is not supported
320      */
321     QueryResults query( WorkspaceType workspace,
322                         AccessQueryRequest accessQuery );
323 
324     /**
325      * Perform a full-text search of this workspace.
326      * 
327      * @param workspace the workspace to be searched; may not be null
328      * @param search the full-text search; may not be null
329      * @return the query results, or null if the query is not supported
330      */
331     QueryResults search( WorkspaceType workspace,
332                          FullTextSearchRequest search );
333 
334     /**
335      * Attempts to lock the given node with the given timeout. If the lock attempt fails, a {@link LockFailedException} will be
336      * thrown.
337      * 
338      * @param workspace the workspace; may not be null
339      * @param node the node to be locked; may not be null
340      * @param lockScope the scope of the lock (i.e., whether descendants of {@code node} should be included in the lock
341      * @param lockTimeoutInMillis the maximum lifetime of the lock in milliseconds; zero (0) indicates that the connector default
342      *        should be used
343      * @throws LockFailedException if the implementing connector supports locking but the lock could not be acquired.
344      */
345     void lockNode( WorkspaceType workspace,
346                    NodeType node,
347                    LockScope lockScope,
348                    long lockTimeoutInMillis ) throws LockFailedException;
349 
350     /**
351      * Attempts to unlock the given node.
352      * 
353      * @param workspace the workspace; may not be null
354      * @param node the node to be unlocked; may not be null
355      */
356     void unlockNode( WorkspaceType workspace,
357                      NodeType node );
358 
359     /**
360      * Commit any changes that have been made to the repository. This method may throw runtime exceptions if there are failures
361      * committing the changes, but the transaction is still expected to be closed.
362      * 
363      * @see #rollback()
364      */
365     void commit();
366 
367     /**
368      * Rollback any changes that have been made to this repository. This method may throw runtime exceptions if there are failures
369      * rolling back the changes, but the transaction is still expected to be closed.
370      * 
371      * @see #commit()
372      */
373     void rollback();
374 
375 }