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 }