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.jackrabbit;
35
36 import info.magnolia.cms.beans.config.ContentRepository;
37 import info.magnolia.cms.core.Path;
38 import info.magnolia.cms.core.SystemProperty;
39 import info.magnolia.repository.Provider;
40 import info.magnolia.repository.RepositoryNotInitializedException;
41 import info.magnolia.repository.definition.RepositoryDefinition;
42
43 import java.io.File;
44 import java.io.FileInputStream;
45 import java.io.FileNotFoundException;
46 import java.io.IOException;
47 import java.io.InputStream;
48 import java.lang.reflect.InvocationTargetException;
49 import java.lang.reflect.Method;
50 import java.util.Hashtable;
51 import java.util.Iterator;
52 import java.util.Map;
53
54 import javax.jcr.NamespaceException;
55 import javax.jcr.Repository;
56 import javax.jcr.RepositoryException;
57 import javax.jcr.Session;
58 import javax.jcr.SimpleCredentials;
59 import javax.jcr.Workspace;
60 import javax.jcr.nodetype.NoSuchNodeTypeException;
61 import javax.jcr.nodetype.NodeTypeManager;
62 import javax.naming.Context;
63 import javax.naming.InitialContext;
64 import javax.naming.NameNotFoundException;
65 import javax.naming.NamingException;
66 import javax.xml.transform.TransformerFactoryConfigurationError;
67
68 import org.apache.commons.beanutils.PropertyUtils;
69 import org.apache.commons.io.IOUtils;
70 import org.apache.commons.lang.ArrayUtils;
71 import org.apache.commons.lang.StringUtils;
72 import org.apache.commons.lang.SystemUtils;
73 import org.apache.jackrabbit.core.WorkspaceImpl;
74 import org.apache.jackrabbit.core.jndi.RegistryHelper;
75 import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
76 import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
77 import org.apache.jackrabbit.core.nodetype.xml.NodeTypeReader;
78 import org.apache.jackrabbit.spi.Name;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
81
82
83
84
85
86
87
88 public class ProviderImpl implements Provider {
89
90
91
92
93 private static final String MAGNOLIA_CLUSTERID_PROPERTY = "magnolia.clusterid";
94
95
96
97
98 private static final String JACKRABBIT_CLUSTER_ID_PROPERTY = "org.apache.jackrabbit.core.cluster.node_id";
99
100 private static final Logger log = LoggerFactory.getLogger(ProviderImpl.class);
101
102 private static final String CONFIG_FILENAME_KEY = "configFile";
103
104 private static final String REPOSITORY_HOME_KEY = "repositoryHome";
105
106 private static final String CONTEXT_FACTORY_CLASS_KEY = "contextFactoryClass";
107
108 private static final String PROVIDER_URL_KEY = "providerURL";
109
110 private static final String BIND_NAME_KEY = "bindName";
111
112 private static final String MGNL_NODETYPES = "/mgnl-nodetypes/magnolia-nodetypes.xml";
113
114 private static final String CUSTOM_NODETYPES = "customNodeTypes";
115
116 private RepositoryDefinition repositoryMapping;
117
118 private Repository repository;
119
120 private String bindName;
121
122 private Hashtable<String, Object> jndiEnv;
123
124 private static final String REPO_HOME_PREFIX = "${repository.home}";
125
126 private static final int REPO_HOME_SUFIX_LEN = REPO_HOME_PREFIX.length();
127
128 private static final String sysRepositoryHome = System.getProperty("repository.home");
129
130 private static final String sysRepositoryHomes = System.getProperty("repository.homes");
131
132
133
134
135
136
137 private String getRepositoryHome(final String repositoryHome) {
138 boolean relocate = false;
139 String tmp = repositoryHome;
140 if (repositoryHome.startsWith(REPOSITORY_HOME_KEY)) {
141 tmp = repositoryHome.substring(REPO_HOME_SUFIX_LEN);
142 relocate = true;
143 }
144
145
146
147 if (sysRepositoryHome != null && relocate) {
148 return sysRepositoryHome + File.separator + tmp;
149 }
150
151
152
153
154 if (sysRepositoryHomes != null) {
155 return sysRepositoryHomes + File.separator + tmp;
156 }
157
158
159
160
161 return Path.getAbsoluteFileSystemPath(tmp);
162 }
163
164
165
166
167 @Override
168 public void init(RepositoryDefinition repositoryMapping) throws RepositoryNotInitializedException {
169 checkXmlSettings();
170
171 this.repositoryMapping = repositoryMapping;
172
173 Map params = this.repositoryMapping.getParameters();
174 String configFile = (String) params.get(CONFIG_FILENAME_KEY);
175 configFile = Path.getAbsoluteFileSystemPath(configFile);
176 String repositoryHome = (String) params.get(REPOSITORY_HOME_KEY);
177 repositoryHome = getRepositoryHome(repositoryHome);
178
179
180 try {
181 File repoHomeFile = new File(repositoryHome);
182 repositoryHome = repoHomeFile.getCanonicalPath();
183 }
184 catch (IOException e1) {
185
186 }
187
188 String clusterid = SystemProperty.getProperty(MAGNOLIA_CLUSTERID_PROPERTY);
189 if (StringUtils.isNotBlank(clusterid)) {
190 System.setProperty(JACKRABBIT_CLUSTER_ID_PROPERTY, clusterid);
191 }
192
193
194 clusterid = System.getProperty(JACKRABBIT_CLUSTER_ID_PROPERTY);
195
196 log.info("Loading repository at {} (config file: {}) - cluster id: \"{}\"", new Object[]{
197 repositoryHome,
198 configFile,
199 StringUtils.defaultString(clusterid, "<unset>")});
200
201 bindName = (String) params.get(BIND_NAME_KEY);
202 jndiEnv = new Hashtable<String, Object>();
203 jndiEnv.put(Context.INITIAL_CONTEXT_FACTORY, params.get(CONTEXT_FACTORY_CLASS_KEY));
204 jndiEnv.put(Context.PROVIDER_URL, params.get(PROVIDER_URL_KEY));
205
206 try {
207 InitialContext ctx = new InitialContext(jndiEnv);
208
209 try {
210 this.repository = (Repository) ctx.lookup(bindName);
211 }
212 catch (NameNotFoundException ne) {
213 log.debug("No JNDI bound Repository found with name {}, trying to initialize a new Repository", bindName);
214 RegistryHelper.registerRepository(ctx, bindName, configFile, repositoryHome, true);
215 this.repository = (Repository) ctx.lookup(bindName);
216 }
217 this.validateWorkspaces();
218 }
219 catch (NamingException e) {
220 log.error("Unable to initialize repository: " + e.getMessage(), e);
221 throw new RepositoryNotInitializedException(e);
222 }
223 catch (RepositoryException e) {
224 log.error("Unable to initialize repository: " + e.getMessage(), e);
225 throw new RepositoryNotInitializedException(e);
226 }
227 catch (TransformerFactoryConfigurationError e) {
228 log.error("Unable to initialize repository: " + e.getMessage(), e);
229 throw new RepositoryNotInitializedException(e);
230 }
231 }
232
233 @Override
234 public void shutdownRepository() {
235 log.info("Shutting down repository bound to '{}'", bindName);
236
237 try {
238 Context ctx = new InitialContext(jndiEnv);
239 RegistryHelper.unregisterRepository(ctx, bindName);
240 } catch (NamingException e) {
241 log.warn("Unable to shutdown repository " + bindName + ": " + e.getMessage(), e);
242 } catch (Throwable e) {
243 log.error("Failed to shutdown repository " + bindName + ": " + e.getMessage(), e);
244 }
245 }
246
247
248
249
250 @Override
251 public Repository getUnderlineRepository() throws RepositoryNotInitializedException {
252 return getUnderlyingRepository();
253 }
254
255 @Override
256 public Repository getUnderlyingRepository() throws RepositoryNotInitializedException {
257 if (this.repository == null) {
258 throw new RepositoryNotInitializedException("Null repository");
259 }
260 return this.repository;
261 }
262
263
264
265
266 @Override
267 public void registerNamespace(String namespacePrefix, String uri, Workspace workspace) throws RepositoryException {
268 try {
269 workspace.getNamespaceRegistry().getURI(namespacePrefix);
270 }
271 catch (NamespaceException e) {
272 if (log.isDebugEnabled()) {
273 log.debug(e.getMessage());
274 }
275 log.info("Registering prefix [{}] with URI {}", namespacePrefix, uri);
276 workspace.getNamespaceRegistry().registerNamespace(namespacePrefix, uri);
277 }
278 }
279
280
281
282
283 @Override
284 public void unregisterNamespace(String prefix, Workspace workspace) throws RepositoryException {
285 workspace.getNamespaceRegistry().unregisterNamespace(prefix);
286 }
287
288
289
290
291 @Override
292 public void registerNodeTypes() throws RepositoryException {
293 registerNodeTypes(StringUtils.EMPTY);
294 }
295
296
297
298
299 @Override
300 public void registerNodeTypes(String configuration) throws RepositoryException {
301 if (StringUtils.isEmpty(configuration)) {
302 configuration = this.repositoryMapping.getParameters().get(CUSTOM_NODETYPES);
303 }
304
305 InputStream xml = getNodeTypeDefinition(configuration);
306 this.registerNodeTypes(xml);
307 }
308
309
310
311
312 @Override
313 public void registerNodeTypes(InputStream xmlStream) throws RepositoryException {
314 SimpleCredentials credentials = new SimpleCredentials(
315 ContentRepository.REPOSITORY_USER,
316 ContentRepository.REPOSITORY_PSWD.toCharArray());
317 Session jcrSession = this.repository.login(credentials);
318
319 try {
320
321 Workspace workspace = jcrSession.getWorkspace();
322
323
324 if (xmlStream == null) {
325 throw new MissingNodetypesException();
326 }
327
328
329
330 Object[] types;
331
332 try {
333 types = (Object[]) NodeTypeReader.class.getMethod("read", new Class[]{InputStream.class}).invoke(
334 null,
335 new Object[]{xmlStream});
336 }
337 catch (Exception e) {
338 throw new RepositoryException(e.getMessage(), e);
339 }
340 finally {
341 IOUtils.closeQuietly(xmlStream);
342 }
343
344 NodeTypeManager ntMgr = workspace.getNodeTypeManager();
345 NodeTypeRegistry ntReg;
346 try {
347 ntReg = ((NodeTypeManagerImpl) ntMgr).getNodeTypeRegistry();
348 }
349 catch (ClassCastException e) {
350
351
352 log.debug("Failed to get NodeTypeRegistry: ", e);
353 return;
354 }
355
356 for (int j = 0; j < types.length; j++) {
357 Object def = types[j];
358
359 Name ntname;
360 try {
361 ntname = (Name) PropertyUtils.getProperty(def, "name");
362 }
363 catch (Exception e) {
364 throw new RepositoryException(e.getMessage(), e);
365 }
366
367 try {
368
369
370
371
372 Method method = ntReg.getClass().getMethod("getNodeTypeDef", Name.class);
373 method.invoke(ntReg, ntname);
374 }
375 catch (IllegalArgumentException e)
376 {
377 throw new RepositoryException(e.getMessage(), e);
378 }
379 catch (IllegalAccessException e)
380 {
381 throw new RepositoryException(e.getMessage(), e);
382 }
383 catch (SecurityException e)
384 {
385 throw new RepositoryException(e.getMessage(), e);
386 }
387 catch (NoSuchMethodException e)
388 {
389 throw new RepositoryException(e.getMessage(), e);
390 }
391 catch (InvocationTargetException ite)
392 {
393 if (ite.getTargetException() instanceof NoSuchNodeTypeException)
394 {
395 log.info("Registering nodetype {} on repository {}", ntname, repositoryMapping.getName());
396
397 try
398 {
399
400 getMethod(NodeTypeRegistry.class, "registerNodeType").invoke(ntReg, new Object[]{def });
401 }
402 catch (Exception e)
403 {
404 throw new RepositoryException(e.getMessage(), e);
405 }
406 }
407 }
408 }
409
410 }
411 finally {
412 jcrSession.logout();
413 }
414 }
415
416 private Method getMethod(Class theclass, String methodName) throws NoSuchMethodException {
417 Method[] declaredMethods = theclass.getDeclaredMethods();
418
419 for (Method method : declaredMethods) {
420 if (method.getName().equals(methodName)) {
421 return method;
422 }
423 }
424
425 throw new NoSuchMethodException(theclass.getName() + "." + methodName + "()");
426 }
427
428
429
430
431
432 private InputStream getNodeTypeDefinition(String configuration) {
433
434 InputStream xml;
435
436 if (StringUtils.isNotEmpty(configuration)) {
437
438
439 xml = getClass().getResourceAsStream(configuration);
440 if (xml != null) {
441 log.info("Custom node types registered using {}", configuration);
442 return xml;
443 }
444
445
446 File nodeTypeDefinition = new File(Path.getAbsoluteFileSystemPath(configuration));
447 if (nodeTypeDefinition.exists()) {
448 try {
449 return new FileInputStream(nodeTypeDefinition);
450 }
451 catch (FileNotFoundException e) {
452
453 log.error("File not found: {}", configuration);
454 }
455 }
456
457
458 log.error("Unable to find node type definition: {} for repository {}", configuration, this.repositoryMapping.getName());
459 }
460
461
462 xml = getClass().getResourceAsStream(MGNL_NODETYPES);
463
464 return xml;
465 }
466
467
468
469
470
471
472
473
474 protected void checkXmlSettings() {
475 if (SystemUtils.isJavaVersionAtLeast(1.5f)
476 && "org.apache.xalan.processor.TransformerFactoryImpl".equals(System
477 .getProperty("javax.xml.transform.TransformerFactory"))) {
478
479 String transformerClass = "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl";
480
481 try {
482 Class.forName(transformerClass);
483
484 System.setProperty("javax.xml.transform.TransformerFactory", transformerClass);
485
486 log.info("Java 1.5 detected, setting system property \"javax.xml.transform.TransformerFactory\" to \"{}\"", transformerClass);
487 }
488 catch (Throwable e) {
489
490 }
491 }
492 }
493
494
495
496
497 private void validateWorkspaces() throws RepositoryException {
498 Iterator<String> configuredNames = repositoryMapping.getWorkspaces().iterator();
499 while (configuredNames.hasNext()) {
500 registerWorkspace(configuredNames.next());
501 }
502 }
503
504
505
506
507 @Override
508 public boolean registerWorkspace(String workspaceName) throws RepositoryException {
509
510 SimpleCredentials credentials = new SimpleCredentials(
511 ContentRepository.REPOSITORY_USER,
512 ContentRepository.REPOSITORY_PSWD.toCharArray());
513 Session jcrSession = this.repository.login(credentials);
514
515 try {
516 WorkspaceImpl defaultWorkspace = (WorkspaceImpl) jcrSession.getWorkspace();
517 String[] workspaceNames = defaultWorkspace.getAccessibleWorkspaceNames();
518
519 boolean alreadyExists = ArrayUtils.contains(workspaceNames, workspaceName);
520 if (!alreadyExists) {
521 defaultWorkspace.createWorkspace(workspaceName);
522 }
523 jcrSession.logout();
524
525 return !alreadyExists;
526 } catch (ClassCastException e) {
527
528
529 log.debug("Unable to register workspace, will continue", e);
530 } catch (Throwable t) {
531 log.error("Unable to register workspace, will continue", t);
532 }
533 return false;
534 }
535
536 @Override
537 public Session getSystemSession(String workspaceName) throws RepositoryException {
538
539
540
541 String user = SystemProperty.getProperty("magnolia.connection.jcr.admin.userId", SystemProperty.getProperty("magnolia.connection.jcr.userId", "admin"));
542 String pwd = SystemProperty.getProperty("magnolia.connection.jcr.admin.password", SystemProperty.getProperty("magnolia.connection.jcr.password", "admin"));
543 return this.repository.login(new SimpleCredentials(user, pwd.toCharArray()), workspaceName);
544 }
545
546 }