1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.repository;
35
36 import info.magnolia.audit.MgnlAuditLoggingContentDecorator;
37 import info.magnolia.audit.MgnlAuditLoggingContentDecoratorSessionWrapper;
38 import info.magnolia.cms.core.FileSystemHelper;
39 import info.magnolia.cms.core.version.MgnlVersioningSession;
40 import info.magnolia.context.MgnlContext;
41 import info.magnolia.init.MagnoliaConfigurationProperties;
42 import info.magnolia.jcr.RuntimeRepositoryException;
43 import info.magnolia.jcr.wrapper.MagnoliaSessionContentDecorator;
44 import info.magnolia.jcr.predicate.AbstractPredicate;
45 import info.magnolia.jcr.util.NodeTypes;
46 import info.magnolia.jcr.util.NodeUtil;
47 import info.magnolia.jcr.wrapper.MgnlLogicalWorkspaceNameMappingWorkspaceDecorator;
48 import info.magnolia.jcr.wrapper.MgnlPropertySettingContentDecorator;
49 import info.magnolia.objectfactory.Classes;
50 import info.magnolia.objectfactory.Components;
51 import info.magnolia.repository.definition.RepositoryDefinition;
52 import info.magnolia.repository.definition.RepositoryMappingDefinition;
53 import info.magnolia.repository.definition.RepositoryMappingDefinitionReader;
54 import info.magnolia.repository.definition.WorkspaceMappingDefinition;
55 import info.magnolia.repository.mbean.TrackingSessionWrapper;
56 import info.magnolia.stats.JCRStats;
57
58 import java.io.InputStream;
59 import java.util.Arrays;
60 import java.util.Collection;
61 import java.util.LinkedHashMap;
62 import java.util.LinkedHashSet;
63 import java.util.Map;
64 import java.util.Set;
65
66 import javax.inject.Inject;
67 import javax.inject.Singleton;
68 import javax.jcr.Credentials;
69 import javax.jcr.NoSuchWorkspaceException;
70 import javax.jcr.Node;
71 import javax.jcr.Repository;
72 import javax.jcr.RepositoryException;
73 import javax.jcr.Session;
74 import javax.jcr.Workspace;
75
76 import org.apache.commons.io.IOUtils;
77 import org.apache.commons.lang3.StringUtils;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80
81
82
83
84 @Singleton
85 public final class DefaultRepositoryManager implements RepositoryManager {
86
87 private static final Logger log = LoggerFactory.getLogger(DefaultRepositoryManager.class);
88
89 private final WorkspaceMapping workspaceMapping;
90 private final MagnoliaConfigurationProperties magnoliaConfigurationProperties;
91 private final FileSystemHelper fileSystemHelper;
92
93 @Inject
94 public DefaultRepositoryManager(MagnoliaConfigurationProperties magnoliaConfigurationProperties, WorkspaceMapping workspaceMapping, FileSystemHelper fileSystemHelper) {
95 this.magnoliaConfigurationProperties = magnoliaConfigurationProperties;
96 this.workspaceMapping = workspaceMapping;
97 this.fileSystemHelper = fileSystemHelper;
98 }
99
100
101
102
103 @Deprecated
104 public DefaultRepositoryManager() {
105 this(Components.getComponent(MagnoliaConfigurationProperties.class), new WorkspaceMapping(), Components.getComponent(FileSystemHelper.class));
106 }
107
108
109
110
111 @Deprecated
112 public DefaultRepositoryManager(MagnoliaConfigurationProperties magnoliaConfigurationProperties, WorkspaceMapping workspaceMapping) {
113 this(magnoliaConfigurationProperties, workspaceMapping, Components.getComponent(FileSystemHelper.class));
114 }
115
116 @Override
117 public void init() {
118 log.info("Loading JCR");
119 workspaceMapping.clearRepositories();
120 try {
121 loadRepositories();
122 log.debug("JCR loaded");
123 } catch (Exception e) {
124 log.error(e.getMessage(), e);
125 }
126 }
127
128 @Override
129 public void shutdown() {
130 log.info("Shutting down JCR");
131 for (RepositoryDefinition repositoryDefinition : workspaceMapping.getRepositoryDefinitions()) {
132 Provider provider = workspaceMapping.getRepositoryProvider(repositoryDefinition.getName());
133 provider.shutdownRepository();
134 }
135 workspaceMapping.clearAll();
136 }
137
138 @Override
139 public boolean checkIfInitialized() throws RepositoryException {
140 Collection<String> workspaceNames = workspaceMapping.getLogicalWorkspaceNames();
141 for (String workspace : workspaceNames) {
142 if (checkIfInitialized(workspace)) {
143 return true;
144 }
145 }
146 return false;
147 }
148
149 @Override
150 public boolean checkIfInitialized(String logicalWorkspace) throws RepositoryException {
151 log.debug("Checking [{}] repository.", logicalWorkspace);
152
153 Session session = MgnlContext.getSystemContext().getJCRSession(logicalWorkspace);
154
155 if (session == null) {
156 throw new RuntimeException("Repository [" + logicalWorkspace + "] not loaded");
157 }
158
159 Node startPage = session.getRootNode();
160
161
162 Iterable<Node> children = NodeUtil.getNodes(startPage, new AbstractPredicate<Node>() {
163 @Override
164 public boolean evaluateTyped(Node content) {
165 String name;
166 try {
167 name = content.getName();
168 } catch (RepositoryException e) {
169 throw new RuntimeRepositoryException(e);
170 }
171 return (!name.startsWith(NodeTypes.JCR_PREFIX) && !name.startsWith(NodeTypes.REP_PREFIX));
172 }
173 });
174
175 if (children.iterator().hasNext()) {
176 log.debug("Content found in [{}].", logicalWorkspace);
177 return true;
178 }
179 return false;
180 }
181
182 @Override
183 public void reload() {
184
185
186
187 log.info("Reloading JCR");
188 init();
189 }
190
191 private void loadRepositories() throws Exception {
192 final String path = magnoliaConfigurationProperties.getProperty(MagnoliaConfigurationProperties.MAGNOLIA_REPOSITORIES_CONFIG);
193 if (path == null) {
194 throw new RepositoryNotInitializedException("No value found for property " + MagnoliaConfigurationProperties.MAGNOLIA_REPOSITORIES_CONFIG + ": can not start repository.");
195 }
196 final String tokenizedConfig = fileSystemHelper.getTokenizedConfigFile(path);
197 InputStream stream = IOUtils.toInputStream(tokenizedConfig);
198
199 RepositoryMappingDefinitionReader reader = new RepositoryMappingDefinitionReader();
200 RepositoryMappingDefinition mapping = reader.read(stream);
201
202 Map<String, WorkspaceMappingDefinition> workspaceMappingDefinitions = new LinkedHashMap<>();
203
204 for (WorkspaceMappingDefinition definition : mapping.getWorkspaceMappings()) {
205 if (StringUtils.equals(RepositoryConstants.VERSION_STORE, definition.getLogicalWorkspaceName()) || StringUtils.equals(RepositoryConstants.VERSION_STORE, definition.getLogicalWorkspaceName())) {
206 log.warn("Please remove {} workspace definition from the repositories.xml configuration, this workspace is created automatically for each repository thus does not need to be specified in the configuration file.", RepositoryConstants.VERSION_STORE);
207 } else if (StringUtils.equals(RepositoryConstants.SYSTEM, definition.getLogicalWorkspaceName()) || StringUtils.equals(RepositoryConstants.SYSTEM, definition.getPhysicalWorkspaceName())) {
208 log.warn("Please remove {} workspace definition from the repositories.xml configuration, this workspace is created automatically for each repository thus does not need to be specified in the configuration file.", RepositoryConstants.SYSTEM);
209 } else {
210 workspaceMappingDefinitions.put(definition.getLogicalWorkspaceName(), definition);
211 }
212 }
213
214 mapping.getWorkspaceMappings().clear();
215 mapping.setMappings(workspaceMappingDefinitions);
216
217 for (RepositoryDefinition repositoryDefinition : mapping.getRepositories()) {
218 if (repositoryDefinition.getWorkspaces().isEmpty()) {
219 repositoryDefinition.addWorkspace("default");
220 }
221 workspaceMapping.addRepositoryDefinition(repositoryDefinition);
222 loadRepository(repositoryDefinition);
223 }
224
225 for (WorkspaceMappingDefinition workspaceMapping : mapping.getWorkspaceMappings()) {
226 this.workspaceMapping.addWorkspaceMappingDefinition(workspaceMapping);
227 }
228
229
230 for (RepositoryDefinition repoDefinition : workspaceMapping.getRepositoryDefinitions()) {
231 String repoName = repoDefinition.getName();
232 Provider provider = workspaceMapping.getRepositoryProvider(repoName);
233 Session session = provider.getSystemSession("default");
234 try {
235 for (String wksName : session.getWorkspace().getAccessibleWorkspaceNames()) {
236 if (!hasWorkspace(wksName)) {
237 loadWorkspace(repoName, wksName);
238 }
239 }
240 } finally {
241 session.logout();
242 }
243 }
244 }
245
246 @Override
247 public void loadRepository(RepositoryDefinition definition) throws RepositoryNotInitializedException, InstantiationException, IllegalAccessException, ClassNotFoundException {
248 log.info("Loading JCR {}", definition.getName());
249
250
251 Set<String> workspaces = new LinkedHashSet<>(definition.getWorkspaces());
252 workspaces.addAll(Arrays.asList(RepositoryConstants.SYSTEM, RepositoryConstants.VERSION_STORE));
253
254 definition.getWorkspaces().clear();
255 definition.getWorkspaces().addAll(workspaces);
256
257 Class<? extends Provider> providerClass = Classes.getClassFactory().forName(definition.getProvider());
258 Provider provider = Components.getComponentProvider().newInstance(providerClass);
259 provider.init(definition);
260 Repository repository = provider.getUnderlyingRepository();
261 workspaceMapping.setRepository(definition.getName(), repository);
262 workspaceMapping.setRepositoryProvider(definition.getName(), provider);
263
264 if (definition.isLoadOnStartup()) {
265 for (String workspaceId : workspaces) {
266 registerNameSpacesAndNodeTypes(workspaceId, definition, provider);
267 }
268 }
269 }
270
271 @Override
272 public void loadWorkspace(String repositoryId, String physicalWorkspaceName) throws RepositoryException {
273 String logicalWorkspaceName;
274
275 if (StringUtils.isNotBlank(repositoryId) && (RepositoryConstants.SYSTEM.equals(physicalWorkspaceName) || RepositoryConstants.VERSION_STORE.equals(physicalWorkspaceName))) {
276 logicalWorkspaceName = repositoryId + "-" + physicalWorkspaceName;
277 } else {
278 logicalWorkspaceName = physicalWorkspaceName;
279 }
280
281 log.info("Loading workspace {} (logical name {}).", physicalWorkspaceName, logicalWorkspaceName);
282
283 workspaceMapping.addWorkspaceMapping(new WorkspaceMappingDefinition(logicalWorkspaceName, repositoryId, physicalWorkspaceName));
284
285 Provider provider = getRepositoryProvider(repositoryId);
286 provider.registerWorkspace(physicalWorkspaceName);
287 RepositoryDefinition repositoryDefinition = workspaceMapping.getRepositoryDefinition(repositoryId);
288
289 registerNameSpacesAndNodeTypes(physicalWorkspaceName, repositoryDefinition, provider);
290 }
291
292 private void registerNameSpacesAndNodeTypes(String physicalWorkspaceName, RepositoryDefinition repositoryDefinition, Provider provider) {
293 try {
294 Session session = provider.getSystemSession(physicalWorkspaceName);
295 try {
296 provider.registerNamespace(RepositoryConstants.NAMESPACE_PREFIX, RepositoryConstants.NAMESPACE_URI, session.getWorkspace());
297 provider.registerNodeTypes();
298 } finally {
299 session.logout();
300 }
301 } catch (RepositoryException e) {
302 log.error("Failed to initialize workspace {} in repository {}", physicalWorkspaceName, repositoryDefinition.getName(), e);
303 }
304 }
305
306 @Override
307 public Session getSession(String logicalWorkspaceName, Credentials credentials) throws RepositoryException {
308 WorkspaceMappingDefinition mapping = this.workspaceMapping.getWorkspaceMapping(logicalWorkspaceName);
309 if (mapping == null) throw new NoSuchWorkspaceException(logicalWorkspaceName);
310 Repository repository = getRepository(mapping.getRepositoryName());
311 String physicalWorkspaceName = mapping.getPhysicalWorkspaceName();
312
313 Session session = repository.login(credentials, physicalWorkspaceName);
314 return wrapSession(session, logicalWorkspaceName);
315 }
316
317 @Override
318 public Session getSystemSession(String logicalWorkspaceName) throws RepositoryException {
319 WorkspaceMappingDefinition mapping = this.workspaceMapping.getWorkspaceMapping(logicalWorkspaceName);
320 if (mapping == null) {
321 throw new NoSuchWorkspaceException(logicalWorkspaceName);
322 }
323 Provider provider = getRepositoryProvider(mapping.getRepositoryName());
324 return wrapSession(provider.getSystemSession(mapping.getPhysicalWorkspaceName()), logicalWorkspaceName);
325 }
326
327 @Override
328 public void createWorkspace(String repository, String logicalWorkspaceName) throws RepositoryException {
329 for (WorkspaceMappingDefinition mapping : workspaceMapping.getWorkspaceMappings()) {
330 Session session = getSystemSession(mapping.getLogicalWorkspaceName());
331 try {
332 if (mapping.getRepositoryName().equals(repository)) {
333 Workspace workspace = session.getWorkspace();
334 workspace.createWorkspace(logicalWorkspaceName);
335 workspaceMapping.addWorkspaceMapping(new WorkspaceMappingDefinition(logicalWorkspaceName, repository, logicalWorkspaceName));
336 return;
337 }
338 } finally {
339 session.logout();
340 }
341 }
342 throw new RepositoryException("Repository [" + repository + "] doesn't exist.");
343 }
344
345 private Session wrapSession(Session session, String logicalWorkspaceName) {
346 session = new TrackingSessionWrapper(session, JCRStats.getInstance());
347 session = new MgnlLogicalWorkspaceNameMappingWorkspaceDecorator(logicalWorkspaceName, session.getWorkspace().getName()).wrapSession(session);
348 if (logicalWorkspaceName.contains(RepositoryConstants.SYSTEM)) {
349 return new MgnlVersioningSession(session);
350 }
351 if (!logicalWorkspaceName.contains(RepositoryConstants.VERSION_STORE)) {
352
353 session = new MgnlVersioningSession(session);
354 }
355
356 session = new MgnlPropertySettingContentDecorator().wrapSession(session);
357 if (!"imaging".equals(logicalWorkspaceName)) {
358
359 session = new MgnlAuditLoggingContentDecoratorSessionWrapper(session, new MgnlAuditLoggingContentDecorator());
360 }
361 return new MagnoliaSessionContentDecorator().wrapSession(session);
362 }
363
364 @Override
365 public String getRepositoryNameForWorkspace(String logicalWorkspaceName) {
366 if (hasWorkspace(logicalWorkspaceName)) {
367 return workspaceMapping.getWorkspaceMapping(logicalWorkspaceName).getRepositoryName();
368 }
369 throw new IllegalStateException("No repository known for logical workspace name " + logicalWorkspaceName);
370 }
371
372 @Override
373 public boolean hasRepository(String repositoryId) {
374 return workspaceMapping.getRepositoryDefinition(repositoryId) != null;
375 }
376
377 @Override
378 public RepositoryDefinition getRepositoryDefinition(String repositoryId) {
379 return workspaceMapping.getRepositoryDefinition(repositoryId);
380 }
381
382 @Override
383 public Provider getRepositoryProvider(String repositoryId) {
384 return workspaceMapping.getRepositoryProvider(repositoryId);
385 }
386
387 @Override
388 public Repository getRepository(String repositoryId) {
389 return workspaceMapping.getRepository(repositoryId);
390 }
391
392 @Override
393 public void addWorkspaceMapping(WorkspaceMappingDefinition mapping) {
394 workspaceMapping.addWorkspaceMapping(mapping);
395 }
396
397 @Override
398 public boolean hasWorkspace(String logicalWorkspaceName) {
399 return workspaceMapping.getWorkspaceMapping(logicalWorkspaceName) != null;
400 }
401
402 @Override
403 public Collection<WorkspaceMappingDefinition> getWorkspaceMappings() {
404 return workspaceMapping.getWorkspaceMappings();
405 }
406
407 @Override
408 public WorkspaceMappingDefinition getWorkspaceMapping(String logicalWorkspaceName) {
409 return workspaceMapping.getWorkspaceMapping(logicalWorkspaceName);
410 }
411
412 @Override
413 public Collection<String> getWorkspaceNames() {
414 return workspaceMapping.getLogicalWorkspaceNames();
415 }
416
417 @Override
418 public Collection<RepositoryDefinition> getRepositoryDefinitions() {
419 return workspaceMapping.getRepositoryDefinitions();
420 }
421
422
423
424
425
426
427 public boolean isClusteredWorkspace(String workspace) {
428 String clusterConfigFile = magnoliaConfigurationProperties.getProperty(MagnoliaConfigurationProperties.MAGNOLIA_REPOSITORIES_CLUSTER_CONFIG);
429 if (StringUtils.isBlank(clusterConfigFile)) {
430 return false;
431 }
432
433 Collection<RepositoryDefinition> repoDefinitions = workspaceMapping.getRepositoryDefinitions();
434 for (RepositoryDefinition repoDefinition : repoDefinitions) {
435 if (repoDefinition.getParameters().containsValue(clusterConfigFile) && repoDefinition.getWorkspaces().contains(workspace)) {
436 return true;
437 }
438 }
439
440 return false;
441 }
442
443 public boolean isClusterMaster() {
444 return magnoliaConfigurationProperties.hasProperty(MagnoliaConfigurationProperties.MAGNOLIA_REPOSITORIES_CLUSTER_MASTER) &&
445 magnoliaConfigurationProperties.getBooleanProperty(MagnoliaConfigurationProperties.MAGNOLIA_REPOSITORIES_CLUSTER_MASTER);
446 }
447 }