1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.modeshape.jcr;
25
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.Map;
34 import java.util.Set;
35 import java.util.concurrent.ScheduledExecutorService;
36 import java.util.concurrent.ScheduledThreadPoolExecutor;
37 import java.util.concurrent.TimeUnit;
38 import java.util.concurrent.locks.Lock;
39 import java.util.concurrent.locks.ReentrantLock;
40 import javax.jcr.Repository;
41 import javax.jcr.RepositoryException;
42 import net.jcip.annotations.ThreadSafe;
43 import org.modeshape.cnd.CndImporter;
44 import org.modeshape.common.util.CheckArg;
45 import org.modeshape.common.util.Logger;
46 import org.modeshape.graph.ExecutionContext;
47 import org.modeshape.graph.Graph;
48 import org.modeshape.graph.Location;
49 import org.modeshape.graph.Node;
50 import org.modeshape.graph.Subgraph;
51 import org.modeshape.graph.connector.RepositoryConnectionFactory;
52 import org.modeshape.graph.connector.RepositorySource;
53 import org.modeshape.graph.connector.RepositorySourceCapabilities;
54 import org.modeshape.graph.io.GraphBatchDestination;
55 import org.modeshape.graph.property.Name;
56 import org.modeshape.graph.property.Path;
57 import org.modeshape.graph.property.PathFactory;
58 import org.modeshape.graph.property.PathNotFoundException;
59 import org.modeshape.graph.property.Property;
60 import org.modeshape.graph.property.basic.GraphNamespaceRegistry;
61 import org.modeshape.jcr.JcrRepository.Option;
62 import org.modeshape.repository.ModeShapeConfiguration;
63 import org.modeshape.repository.ModeShapeEngine;
64
65
66
67
68 @ThreadSafe
69 public class JcrEngine extends ModeShapeEngine {
70
71 final static int LOCK_SWEEP_INTERVAL_IN_MILLIS = 30000;
72 final static int LOCK_EXTENSION_INTERVAL_IN_MILLIS = LOCK_SWEEP_INTERVAL_IN_MILLIS * 2;
73
74 private static final Logger log = Logger.getLogger(ModeShapeEngine.class);
75
76 private final Map<String, JcrRepository> repositories;
77 private final Lock repositoriesLock;
78
79
80
81
82 private final ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(2);
83
84 JcrEngine( ExecutionContext context,
85 ModeShapeConfiguration.ConfigurationDefinition configuration ) {
86 super(context, configuration);
87 this.repositories = new HashMap<String, JcrRepository>();
88 this.repositoriesLock = new ReentrantLock();
89 }
90
91
92
93
94
95
96
97
98
99 void cleanUpLocks() {
100 Collection<JcrRepository> repos;
101
102 try {
103
104 repositoriesLock.lock();
105 repos = new ArrayList<JcrRepository>(repositories.values());
106 } finally {
107 repositoriesLock.unlock();
108 }
109
110 for (JcrRepository repository : repos) {
111 try {
112 repository.cleanUpLocks();
113 } catch (Throwable t) {
114 log.error(t, JcrI18n.errorCleaningUpLocks, repository.getRepositorySourceName());
115 }
116 }
117 }
118
119 @Override
120 public void shutdown() {
121 scheduler.shutdown();
122 super.shutdown();
123
124 try {
125 this.repositoriesLock.lock();
126
127 for (JcrRepository repository : repositories.values()) {
128 repository.close();
129 }
130 this.repositories.clear();
131 } finally {
132 this.repositoriesLock.unlock();
133 }
134 }
135
136 @Override
137 public boolean awaitTermination( long timeout,
138 TimeUnit unit ) throws InterruptedException {
139 if (!scheduler.awaitTermination(timeout, unit)) return false;
140
141 return super.awaitTermination(timeout, unit);
142 }
143
144 @Override
145 public void start() {
146 super.start();
147
148 final JcrEngine engine = this;
149 Runnable cleanUpTask = new Runnable() {
150
151 public void run() {
152 engine.cleanUpLocks();
153 }
154
155 };
156 scheduler.scheduleAtFixedRate(cleanUpTask,
157 LOCK_SWEEP_INTERVAL_IN_MILLIS,
158 LOCK_SWEEP_INTERVAL_IN_MILLIS,
159 TimeUnit.MILLISECONDS);
160 }
161
162
163
164
165
166
167
168
169
170
171 public final JcrRepository getRepository( String repositoryName ) throws RepositoryException {
172 CheckArg.isNotEmpty(repositoryName, "repositoryName");
173 checkRunning();
174 try {
175 repositoriesLock.lock();
176 JcrRepository repository = repositories.get(repositoryName);
177 if (repository == null) {
178 try {
179 repository = doCreateJcrRepository(repositoryName);
180 } catch (PathNotFoundException e) {
181
182 String msg = JcrI18n.repositoryDoesNotExist.text(repositoryName);
183 throw new RepositoryException(msg);
184 }
185 repositories.put(repositoryName, repository);
186 }
187 return repository;
188 } finally {
189 repositoriesLock.unlock();
190 }
191 }
192
193
194
195
196
197
198 public Set<String> getRepositoryNames() {
199 checkRunning();
200 Set<String> results = new HashSet<String>();
201
202 PathFactory pathFactory = getExecutionContext().getValueFactories().getPathFactory();
203 Path repositoriesPath = pathFactory.create(configuration.getPath(), ModeShapeLexicon.REPOSITORIES);
204 Graph configuration = getConfigurationGraph();
205 for (Location child : configuration.getChildren().of(repositoriesPath)) {
206 Name repositoryName = child.getPath().getLastSegment().getName();
207 results.add(readable(repositoryName));
208 }
209 return Collections.unmodifiableSet(results);
210 }
211
212 protected JcrRepository doCreateJcrRepository( String repositoryName ) throws RepositoryException, PathNotFoundException {
213 RepositoryConnectionFactory connectionFactory = getRepositoryConnectionFactory();
214 Map<String, String> descriptors = new HashMap<String, String>();
215 Map<Option, String> options = new HashMap<Option, String>();
216
217
218 PathFactory pathFactory = getExecutionContext().getValueFactories().getPathFactory();
219 Path repositoriesPath = pathFactory.create(configuration.getPath(), ModeShapeLexicon.REPOSITORIES);
220 Path repositoryPath = pathFactory.create(repositoriesPath, repositoryName);
221 Graph configuration = getConfigurationGraph();
222 Subgraph subgraph = configuration.getSubgraphOfDepth(6).at(repositoryPath);
223
224
225 Node optionsNode = subgraph.getNode(ModeShapeLexicon.OPTIONS);
226 if (optionsNode != null) {
227 for (Location optionLocation : optionsNode.getChildren()) {
228 Node optionNode = configuration.getNodeAt(optionLocation);
229 Path.Segment segment = optionLocation.getPath().getLastSegment();
230 Property valueProperty = optionNode.getProperty(ModeShapeLexicon.VALUE);
231 if (valueProperty == null) continue;
232 Option option = Option.findOption(segment.getName().getLocalName());
233 if (option == null) continue;
234 options.put(option, valueProperty.getFirstValue().toString());
235 }
236 }
237
238
239 Node descriptorsNode = subgraph.getNode(ModeShapeLexicon.DESCRIPTORS);
240 if (descriptorsNode != null) {
241 for (Location descriptorLocation : descriptorsNode.getChildren()) {
242 Node optionNode = configuration.getNodeAt(descriptorLocation);
243 Path.Segment segment = descriptorLocation.getPath().getLastSegment();
244 Property valueProperty = optionNode.getProperty(ModeShapeLexicon.VALUE);
245 if (valueProperty == null) continue;
246 descriptors.put(segment.getName().getLocalName(), valueProperty.getFirstValue().toString());
247 }
248 }
249
250
251 ExecutionContext context = getExecutionContext();
252 Node namespacesNode = subgraph.getNode(ModeShapeLexicon.NAMESPACES);
253 if (namespacesNode != null) {
254 GraphNamespaceRegistry registry = new GraphNamespaceRegistry(configuration, namespacesNode.getLocation().getPath(),
255 ModeShapeLexicon.NAMESPACE_URI);
256 context = context.with(registry);
257 }
258
259
260 Property property = subgraph.getRoot().getProperty(ModeShapeLexicon.SOURCE_NAME);
261 if (property == null || property.isEmpty()) {
262 String readableName = readable(ModeShapeLexicon.SOURCE_NAME);
263 String readablePath = readable(subgraph.getLocation());
264 String msg = JcrI18n.propertyNotFoundOnNode.text(readableName, readablePath, configuration.getCurrentWorkspaceName());
265 throw new RepositoryException(msg);
266 }
267 String sourceName = context.getValueFactories().getStringFactory().create(property.getFirstValue());
268
269
270 RepositorySource source = getRepositorySource(sourceName);
271 RepositorySourceCapabilities capabilities = source != null ? source.getCapabilities() : null;
272
273 JcrRepository repository = new JcrRepository(context, connectionFactory, sourceName,
274 getRepositoryService().getRepositoryLibrary(), capabilities, descriptors,
275 options);
276
277
278 Node nodeTypesNode = subgraph.getNode(JcrLexicon.NODE_TYPES);
279 if (nodeTypesNode != null) {
280 boolean needToRefreshSubgraph = false;
281
282
283 Property resourceProperty = nodeTypesNode.getProperty(ModeShapeLexicon.RESOURCE);
284 if (resourceProperty != null) {
285 String resources = this.context.getValueFactories().getStringFactory().create(resourceProperty.getFirstValue());
286
287 for (String resource : resources.split("\\s*,\\s*")) {
288 Graph.Batch batch = configuration.batch();
289 GraphBatchDestination destination = new GraphBatchDestination(batch);
290
291 Path nodeTypesPath = pathFactory.create(repositoryPath, JcrLexicon.NODE_TYPES);
292 CndImporter importer = new CndImporter(destination, nodeTypesPath, false);
293 InputStream is = getClass().getResourceAsStream(resource);
294 try {
295 if (is != null) {
296 importer.importFrom(is, this.getProblems(), resource);
297 batch.execute();
298 needToRefreshSubgraph = true;
299 }
300 } catch (IOException ioe) {
301 ioe.printStackTrace();
302 }
303 }
304
305 }
306
307
308 Subgraph nodeTypesSubgraph = subgraph;
309 if (needToRefreshSubgraph) {
310 nodeTypesSubgraph = configuration.getSubgraphOfDepth(4).at(nodeTypesNode.getLocation().getPath());
311 }
312
313 repository.getRepositoryTypeManager().registerNodeTypes(nodeTypesSubgraph, nodeTypesNode.getLocation());
314
315 }
316
317 return repository;
318 }
319
320 protected final String readable( Name name ) {
321 return name.getString(context.getNamespaceRegistry());
322 }
323
324 protected final String readable( Path path ) {
325 return path.getString(context.getNamespaceRegistry());
326 }
327
328 protected final String readable( Location location ) {
329 return location.getString(context.getNamespaceRegistry());
330 }
331 }