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.Map;
27  import java.util.UUID;
28  import java.util.concurrent.locks.ReadWriteLock;
29  import net.jcip.annotations.NotThreadSafe;
30  
31  /**
32   * The {@link Workspace} implementation that represents all nodes as {@link MapNode} objects and stores them within a
33   * {@link Map} keyed by their UUID.
34   * <p>
35   * Subclasses are required to provide thread-safe access and modification of the state within the encapsulated map, since multiple
36   * {@link Transaction} implementations may be {@link Transaction#commit() committing} changes to the map at the same time.
37   * However, this class does not provide any thread-safety, since the nature of the thread-safety will almost certainly depend on
38   * the actual map implementation. For example, a subclass may use a {@link ReadWriteLock lock}, or it may use a map implementation
39   * that provides the thread-safety.
40   * </p>
41   * 
42   * @param <NodeType> the type of node
43   */
44  @NotThreadSafe
45  public class StandardMapWorkspace<NodeType extends MapNode> extends MapWorkspace<NodeType> {
46  
47      private final Map<UUID, NodeType> nodesByUuid;
48  
49      /**
50       * Create a new instance of the workspace.
51       * 
52       * @param name the workspace name; may not be null
53       * @param nodesByUuid the map of nodes keyed by their UUIDs; may not be null
54       * @param rootNode the root node that is expected to already exist in the map
55       */
56      public StandardMapWorkspace( String name,
57                           Map<UUID, NodeType> nodesByUuid,
58                           NodeType rootNode ) {
59          super(name, rootNode);
60          this.nodesByUuid = nodesByUuid;
61          UUID rootNodeUuid = rootNode.getUuid();
62          if (!this.nodesByUuid.containsKey(rootNodeUuid)) {
63              this.nodesByUuid.put(rootNodeUuid, rootNode);
64          }
65          assert this.nodesByUuid != null;
66      }
67  
68      /**
69       * Create a new instance of the workspace.
70       * 
71       * @param name the workspace name; may not be null
72       * @param nodesByUuid the map of nodes keyed by their UUIDs; may not be null
73       * @param originalToClone the workspace that is to be cloned; may not be null
74       */
75      public StandardMapWorkspace( String name,
76                           Map<UUID, NodeType> nodesByUuid,
77                           StandardMapWorkspace<NodeType> originalToClone ) {
78          super(name, originalToClone);
79          this.nodesByUuid = nodesByUuid;
80          this.nodesByUuid.putAll(originalToClone.nodesByUuid); // make a copy
81          assert this.nodesByUuid != null;
82      }
83  
84      /**
85       * Get the node with the supplied UUID.
86       * 
87       * @param uuid the UUID of the node
88       * @return the node state as known by this workspace, or null if no such node exists in this workspace
89       */
90      @Override
91      public NodeType getNode( UUID uuid ) {
92          return nodesByUuid.get(uuid);
93      }
94  
95      /**
96       * Add the node into this workspace's map, overwriting any previous record of the node
97       * 
98       * @param node the new node; may not be null
99       * @return the previous node state, or null if the node is new to this workspace
100      */
101     @Override
102     public NodeType putNode( NodeType node ) {
103         return nodesByUuid.put(node.getUuid(), node);
104     }
105 
106     /**
107      * Remove and return the node with the supplied UUID. This method will never remove the root node.
108      * 
109      * @param uuid the UUID of the node to be removed
110      * @return the node that was removed, or null if the supplied UUID is the root node's UUID or if this workspace does not
111      *         contain a node with the supplied UUID
112      */
113     @Override
114     public NodeType removeNode( UUID uuid ) {
115         return rootNodeUuid.equals(uuid) ? null : nodesByUuid.remove(uuid);
116     }
117 
118     /**
119      * Remove all of the nodes in this workspace, and make sure there is a single root node with no properties and no children.
120      */
121     @Override
122     @SuppressWarnings( "unchecked" )
123     public void removeAll() {
124         NodeType newRootNode = (NodeType)getRootNode().withoutChildren().withoutProperties().freeze();
125         nodesByUuid.clear();
126         nodesByUuid.put(newRootNode.getUuid(), newRootNode);
127     }
128 }