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