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 }