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