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    * Unless otherwise indicated, all code in ModeShape is licensed
10   * 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.federation;
25  
26  import java.util.ArrayList;
27  import java.util.Collections;
28  import java.util.HashMap;
29  import java.util.LinkedList;
30  import java.util.List;
31  import java.util.Map;
32  import net.jcip.annotations.Immutable;
33  import org.modeshape.common.collection.Problems;
34  import org.modeshape.common.collection.ThreadSafeProblems;
35  import org.modeshape.common.util.CheckArg;
36  import org.modeshape.graph.ExecutionContext;
37  import org.modeshape.graph.Location;
38  import org.modeshape.graph.cache.CachePolicy;
39  import org.modeshape.graph.connector.RepositoryContext;
40  
41  /**
42   * The configuration of a single workspace within a {@link FederatedRepositorySource federated repository}.
43   */
44  @Immutable
45  class FederatedWorkspace {
46  
47      private final RepositoryContext repositoryContext;
48      private final String sourceName;
49      private final String workspaceName;
50      private final List<Projection> projections;
51      private final Map<String, List<Projection>> projectionsBySourceName;
52      private final CachePolicy cachePolicy;
53      private final Problems problems;
54      private final Projector projector;
55  
56      /**
57       * Create a configuration for a federated workspace.
58       * 
59       * @param repositoryContext the repository context; may not be null
60       * @param sourceName the name of the federated repository; may not be null
61       * @param workspaceName the name of the federated workspace; may not be null
62       * @param projections the source projections; may not be null
63       * @param cachePolicy the cache policy for this workspace; may be null if there is no policy
64       * @throws IllegalArgumentException if the name is null or is blank
65       */
66      public FederatedWorkspace( RepositoryContext repositoryContext,
67                                 String sourceName,
68                                 String workspaceName,
69                                 Iterable<Projection> projections,
70                                 CachePolicy cachePolicy ) {
71          CheckArg.isNotNull(repositoryContext, "repositoryContext");
72          CheckArg.isNotNull(sourceName, "sourceName");
73          CheckArg.isNotNull(workspaceName, "workspaceName");
74          CheckArg.isNotNull(projections, "projections");
75          this.repositoryContext = repositoryContext;
76          this.workspaceName = workspaceName;
77          this.sourceName = sourceName;
78          this.cachePolicy = cachePolicy;
79          this.problems = new ThreadSafeProblems();
80          List<Projection> projectionList = new ArrayList<Projection>();
81          for (Projection projection : projections) {
82              if (projection == null) continue;
83              if (!projectionList.contains(projection)) {
84                  projectionList.add(projection);
85              }
86          }
87          this.projections = Collections.unmodifiableList(projectionList);
88          CheckArg.isNotEmpty(this.projections, "sourceProjections");
89          this.projectionsBySourceName = new HashMap<String, List<Projection>>();
90          for (Projection projection : this.projections) {
91              String nameOfSource = projection.getSourceName();
92              List<Projection> projectionsForSource = projectionsBySourceName.get(nameOfSource);
93              if (projectionsForSource == null) {
94                  projectionsForSource = new LinkedList<Projection>();
95                  projectionsBySourceName.put(nameOfSource, projectionsForSource);
96              }
97              projectionsForSource.add(projection);
98          }
99  
100         // Create the (most) appropriate projector ...
101         ExecutionContext context = this.repositoryContext.getExecutionContext();
102         Projector projector = MirrorProjector.with(context, projectionList);
103         if (projector == null) projector = BranchedMirrorProjector.with(context, projectionList);
104         if (projector == null) projector = OffsetMirrorProjector.with(context, projectionList);
105         if (projector == null) projector = GeneralProjector.with(context, projectionList);
106         assert projector != null;
107         this.projector = projector;
108     }
109 
110     /**
111      * Get the repository context in which this workspace exists and has been initialized.
112      * 
113      * @return the repository context
114      */
115     public RepositoryContext getRepositoryContext() {
116         return repositoryContext;
117     }
118 
119     /**
120      * Get the name of the federated repository.
121      * 
122      * @return sourceName
123      */
124     public String getSourceName() {
125         return sourceName;
126     }
127 
128     /**
129      * Get the name of this repository
130      * 
131      * @return name
132      */
133     public String getName() {
134         return this.workspaceName;
135     }
136 
137     /**
138      * Get the cache policy for this workspace
139      * 
140      * @return the workspace's cache policy; may be null
141      */
142     public CachePolicy getCachePolicy() {
143         return cachePolicy;
144     }
145 
146     /**
147      * Return the problem associated with this configuration. These problems may change at any time, although the returned
148      * {@link Problems} object is thread-safe.
149      * 
150      * @return the thread-safe problems for this configuration
151      */
152     public Problems getProblems() {
153         return problems;
154     }
155 
156     /**
157      * Return the unmodifiable list of source projections.
158      * 
159      * @return the source projections; never null and never empty
160      */
161     public List<Projection> getProjections() {
162         return projections;
163     }
164 
165     /**
166      * Determine whether this workspace has a projection supplied contribution
167      * 
168      * @param sourceName the name of the source
169      * @param workspaceName the name of the workspace
170      * @return true if this workspace contains a projection that uses the supplied source and workspace
171      */
172     public boolean contains( String sourceName,
173                              String workspaceName ) {
174         List<Projection> projections = this.projectionsBySourceName.get(sourceName);
175         if (projections != null) {
176             for (Projection projection : projections) {
177                 if (projection.getWorkspaceName().equals(workspaceName)) return true;
178             }
179         }
180         return false;
181     }
182 
183     /**
184      * Get the map of projections by their source name. This method provides direct access to the map used by this instance, and
185      * is mutable. This is meant to be called only by subclasses and tests.
186      * 
187      * @return the list of projections for each source
188      */
189     Map<String, List<Projection>> getProjectionsBySourceName() {
190         return projectionsBySourceName;
191     }
192 
193     /**
194      * Project the supplied location in the federated repository into the equivalent projected node(s).
195      * 
196      * @param context the execution context in which the content is being accessed; may not be null
197      * @param location the location in the federated repository; may not be null
198      * @param requiresUpdate true if the operation for which this projection is needed will update the content in some way, or
199      *        false if read-only operations will be performed
200      * @return the projected node, or null if the node does not exist in any projection
201      */
202     public ProjectedNode project( ExecutionContext context,
203                                   Location location,
204                                   boolean requiresUpdate ) {
205         return projector.project(context, location, requiresUpdate);
206     }
207 
208     /**
209      * {@inheritDoc}
210      * 
211      * @see java.lang.Object#hashCode()
212      */
213     @Override
214     public int hashCode() {
215         return this.workspaceName.hashCode();
216     }
217 
218     /**
219      * {@inheritDoc}
220      * 
221      * @see java.lang.Object#equals(java.lang.Object)
222      */
223     @Override
224     public boolean equals( Object obj ) {
225         if (obj == this) return true;
226         if (obj instanceof FederatedWorkspace) {
227             FederatedWorkspace that = (FederatedWorkspace)obj;
228             if (!this.getSourceName().equals(that.getSourceName())) return false;
229             if (!this.getName().equals(that.getName())) return false;
230             if (!this.getProjections().equals(that.getProjections())) return false;
231             return true;
232         }
233         return false;
234     }
235 
236 }