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