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 }