X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;ds=sidebyside;f=server%2Fruntime%2Forg.argeo.server.jackrabbit%2Fsrc%2Fmain%2Fjava%2Forg%2Fargeo%2Fjackrabbit%2FJackrabbitContainer.java;h=10c7af1d05e002359ce4abf758b3ebb7d9c08fa0;hb=484dcb1507e4e35cc282e50522ea7eac7e99a7f9;hp=a708aadd1d67a6eada7401b8bcf94d3cf95ff8ad;hpb=74d57e72f4454df37c709fd4960e39ce9b793761;p=lgpl%2Fargeo-commons.git diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java index a708aadd1..10c7af1d0 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java @@ -16,12 +16,12 @@ package org.argeo.jackrabbit; -import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -40,6 +40,7 @@ import javax.jcr.Node; import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; +import javax.jcr.SimpleCredentials; import javax.jcr.Value; import org.apache.commons.io.FileUtils; @@ -50,16 +51,17 @@ import org.apache.jackrabbit.api.JackrabbitRepository; import org.apache.jackrabbit.commons.NamespaceHelper; import org.apache.jackrabbit.commons.cnd.CndImporter; import org.apache.jackrabbit.core.RepositoryImpl; -import org.apache.jackrabbit.core.TransientRepository; import org.apache.jackrabbit.core.config.RepositoryConfig; import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory; import org.argeo.ArgeoException; import org.argeo.jcr.ArgeoNames; import org.argeo.jcr.JcrUtils; -import org.springframework.context.ResourceLoaderAware; +import org.argeo.security.SystemAuthentication; import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; +import org.springframework.security.Authentication; +import org.springframework.security.context.SecurityContextHolder; +import org.springframework.security.providers.UsernamePasswordAuthenticationToken; import org.springframework.util.SystemPropertyUtils; import org.xml.sax.InputSource; @@ -67,23 +69,24 @@ import org.xml.sax.InputSource; * Wrapper around a Jackrabbit repository which allows to configure it in Spring * and expose it as a {@link Repository}. */ -public class JackrabbitContainer implements Repository, ResourceLoaderAware { +public class JackrabbitContainer implements Repository { private Log log = LogFactory.getLog(JackrabbitContainer.class); + // remote + private String uri = null; + private Credentials remoteSystemCredentials = null; + + // local private Resource configuration; + private RepositoryConfig repositoryConfig; private File homeDirectory; private Resource variables; - private Boolean inMemory = false; - private String uri = null; // wrapped repository private Repository repository; - private RepositoryConfig repositoryConfig; - - // CND - private ResourceLoader resourceLoader; + // data model /** Node type definitions in CND format */ private List cndFiles = new ArrayList(); @@ -97,29 +100,46 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { private Executor systemExecutor; - public void init() throws Exception { + /** + * Empty constructor, {@link #init()} should be called after properties have + * been set + */ + public JackrabbitContainer() { + } + + /** + * Convenience constructor for remote, {@link #init()} is called in the + * constructor. + */ + public JackrabbitContainer(String uri, Credentials remoteSystemCredentials) { + setUri(uri); + setRemoteSystemCredentials(remoteSystemCredentials); + init(); + } + + /** Initializes */ + public void init() { if (repository != null) { // we are just wrapping another repository - importNodeTypeDefinitions(repository); + prepareDataModel(); return; } createJackrabbitRepository(); - // migrate if needed migrate(); // apply new CND files after migration if (cndFiles != null && cndFiles.size() > 0) - importNodeTypeDefinitions(repository); + prepareDataModel(); } - /** Actually creates a new repository. */ + /** Actually creates the new repository. */ protected void createJackrabbitRepository() { long begin = System.currentTimeMillis(); + InputStream configurationIn = null; try { - // remote repository - if (uri != null && !uri.trim().equals("")) { + if (uri != null && !uri.trim().equals("")) {// remote Map params = new HashMap(); params.put( org.apache.jackrabbit.commons.JcrUtils.REPOSITORY_URI, @@ -131,50 +151,52 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { + " not found"); log.info("Initialized Jackrabbit repository " + repository + " from URI " + uri); - // do not perform further initialization since we assume that - // the - // remote repository has been properly configured - return; - } - - // local repository - if (inMemory && getHomeDirectory().exists()) { - FileUtils.deleteDirectory(getHomeDirectory()); - log.warn("Deleted Jackrabbit home directory " - + getHomeDirectory()); - } + // we assume that the remote repository has been properly + // configured + } else {// local + // reset uri to null in order to optimize isRemote() + uri = null; + + // temporary + if (inMemory && getHomeDirectory().exists()) { + FileUtils.deleteDirectory(getHomeDirectory()); + log.warn("Deleted Jackrabbit home directory " + + getHomeDirectory()); + } - Properties vars = getConfigurationProperties(); - InputStream in = configuration.getInputStream(); - try { + // process configuration file + Properties vars = getConfigurationProperties(); + configurationIn = configuration.getInputStream(); vars.put( RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, getHomeDirectory().getCanonicalPath()); - repositoryConfig = RepositoryConfig.create(new InputSource(in), - vars); - } catch (Exception e) { - throw new RuntimeException("Cannot read configuration", e); - } finally { - IOUtils.closeQuietly(in); - } + repositoryConfig = RepositoryConfig.create(new InputSource( + configurationIn), vars); - if (inMemory) - repository = new TransientRepository(repositoryConfig); - else + // + // Actual repository creation + // repository = RepositoryImpl.create(repositoryConfig); - double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; - log.info("Initialized Jackrabbit repository in " + duration - + " s, home: " + getHomeDirectory() + ", config: " - + configuration); + double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; + log.info("Initialized Jackrabbit repository in " + duration + + " s, home: " + getHomeDirectory() + ", config: " + + configuration); + } } catch (Exception e) { throw new ArgeoException("Cannot create Jackrabbit repository " + getHomeDirectory(), e); + } finally { + IOUtils.closeQuietly(configurationIn); } } /** Executes migrations, if needed. */ protected void migrate() { + // Remote migration not supported + if (isRemote()) + return; + // No migration to perform if (dataModelMigrations.size() == 0) return; @@ -246,7 +268,7 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { + File.separator + "jackrabbit-" + UUID.randomUUID()); homeDirectory.mkdirs(); - // will it work if directory is not empty? + // will it work if directory is not empty?? homeDirectory.deleteOnExit(); } } @@ -258,47 +280,39 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { } } - public void dispose() throws Exception { - long begin = System.currentTimeMillis(); - if (repository != null) { - if (repository instanceof JackrabbitRepository) - ((JackrabbitRepository) repository).shutdown(); - else if (repository instanceof RepositoryImpl) - ((RepositoryImpl) repository).shutdown(); - else if (repository instanceof TransientRepository) - ((TransientRepository) repository).shutdown(); - } - - if (inMemory) - if (getHomeDirectory().exists()) { - FileUtils.deleteDirectory(getHomeDirectory()); - if (log.isDebugEnabled()) - log.debug("Deleted Jackrabbit home directory " - + getHomeDirectory()); - } - - double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; - if (uri != null && !uri.trim().equals("")) - log.info("Destroyed Jackrabbit repository with uri " + uri); - else + /** Shutdown the repository */ + public void destroy() throws Exception { + if (repository != null && repository instanceof RepositoryImpl) { + long begin = System.currentTimeMillis(); + ((RepositoryImpl) repository).shutdown(); + if (inMemory) + if (getHomeDirectory().exists()) { + FileUtils.deleteDirectory(getHomeDirectory()); + if (log.isDebugEnabled()) + log.debug("Deleted Jackrabbit home directory " + + getHomeDirectory()); + } + double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; log.info("Destroyed Jackrabbit repository in " + duration + " s, home: " + getHomeDirectory() + ", config " + configuration); + } } /** - * @deprecated explicitly declare {@link #dispose()} as destroy-method + * @deprecated explicitly declare {@link #destroy()} as destroy-method * instead. */ - public void destroy() throws Exception { - log.error("## Declare destroy-method=\"dispose\". in the Jackrabbit container bean"); + public void dispose() throws Exception { + log.error("## Declare destroy-method=\"destroy\". in the Jackrabbit container bean"); + destroy(); } - /** @deprecated explicitly declare {@link #init()} as init-method instead. */ - public void afterPropertiesSet() throws Exception { - log.error("## Declare init-method=\"init\". in the Jackrabbit container bean"); - } + /* + * UTILITIES + */ + /** Generates the properties to use in the configuration. */ protected Properties getConfigurationProperties() { InputStream propsIn = null; Properties vars; @@ -333,34 +347,56 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { } /** - * Import declared node type definitions, trying to update them if they have - * changed. In case of failures an error will be logged but no exception - * will be thrown. + * Import declared node type definitions and register namespaces. Tries to + * update the node definitions if they have changed. In case of failures an + * error will be logged but no exception will be thrown. */ - protected void importNodeTypeDefinitions(final Repository repository) { + protected void prepareDataModel() { + // importing node def on remote si currently not supported + if (isRemote()) + return; + Runnable action = new Runnable() { public void run() { - Reader reader = null; Session session = null; try { - session = repository.login(); - processNewSession(session); - // Load cnds as resources + session = login(); + // register namespaces + if (namespaces.size() > 0) { + NamespaceHelper namespaceHelper = new NamespaceHelper( + session); + namespaceHelper.registerNamespaces(namespaces); + } + // load CND files from classpath or as URL for (String resUrl : cndFiles) { - Resource res = resourceLoader.getResource(resUrl); - byte[] arr = IOUtils.toByteArray(res.getInputStream()); - reader = new InputStreamReader( - new ByteArrayInputStream(arr)); - CndImporter.registerNodeTypes(reader, session, true); + boolean classpath; + if (resUrl.startsWith("classpath:")) { + resUrl = resUrl.substring("classpath:".length()); + classpath = true; + } else if (resUrl.indexOf(':') < 0) { + classpath = true; + } else { + classpath = false; + } + + URL url = classpath ? getClass().getClassLoader() + .getResource(resUrl) : new URL(resUrl); + + Reader reader = null; + try { + reader = new InputStreamReader(url.openStream()); + CndImporter + .registerNodeTypes(reader, session, true); + } finally { + IOUtils.closeQuietly(reader); + } } - session.save(); } catch (Exception e) { log.error( "Cannot import node type definitions " + cndFiles, e); JcrUtils.discardQuietly(session); } finally { - IOUtils.closeQuietly(reader); JcrUtils.logoutQuietly(session); } } @@ -372,7 +408,10 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { action.run(); } - // JCR REPOSITORY (delegated) + /* + * DELEGATED JCR REPOSITORY METHODS + */ + public String getDescriptor(String key) { return getRepository().getDescriptor(key); } @@ -381,20 +420,32 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { return getRepository().getDescriptorKeys(); } - public Session login() throws LoginException, RepositoryException { - Session session = getRepository().login(); - processNewSession(session); - return session; - } - + /** Central login method */ public Session login(Credentials credentials, String workspaceName) throws LoginException, NoSuchWorkspaceException, RepositoryException { + + // retrieve credentials for remote + if (credentials == null && isRemote()) { + Authentication authentication = SecurityContextHolder.getContext() + .getAuthentication(); + if (authentication != null) { + if (authentication instanceof UsernamePasswordAuthenticationToken) { + UsernamePasswordAuthenticationToken upat = (UsernamePasswordAuthenticationToken) authentication; + credentials = new SimpleCredentials(upat.getName(), upat + .getCredentials().toString().toCharArray()); + } else if ((authentication instanceof SystemAuthentication) + && remoteSystemCredentials != null) { + credentials = remoteSystemCredentials; + } + } + } + Session session; try { session = getRepository().login(credentials, workspaceName); } catch (NoSuchWorkspaceException e) { - if (autocreateWorkspaces) + if (autocreateWorkspaces && workspaceName != null) session = createWorkspaceAndLogsIn(credentials, workspaceName); else throw e; @@ -403,26 +454,26 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { return session; } + public Session login() throws LoginException, RepositoryException { + return login(null, null); + } + public Session login(Credentials credentials) throws LoginException, RepositoryException { - Session session = getRepository().login(credentials); - processNewSession(session); - return session; + return login(credentials, null); } public Session login(String workspaceName) throws LoginException, NoSuchWorkspaceException, RepositoryException { - Session session; - try { - session = getRepository().login(workspaceName); - } catch (NoSuchWorkspaceException e) { - if (autocreateWorkspaces) - session = createWorkspaceAndLogsIn(null, workspaceName); - else - throw e; - } - processNewSession(session); - return session; + return login(null, workspaceName); + } + + /** Called after a session has been created, does nothing by default. */ + protected void processNewSession(Session session) { + } + + public Boolean isRemote() { + return uri != null; } /** Wraps access to the repository, making sure it is available. */ @@ -436,15 +487,6 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { return repository; } - protected synchronized void processNewSession(Session session) { - try { - NamespaceHelper namespaceHelper = new NamespaceHelper(session); - namespaceHelper.registerNamespaces(namespaces); - } catch (Exception e) { - throw new ArgeoException("Cannot process new session", e); - } - } - /** * Logs in to the default workspace, creates the required workspace, logs * out, logs in to the required workspace. @@ -459,10 +501,6 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { return getRepository().login(credentials, workspaceName); } - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - public boolean isStandardDescriptor(String key) { return getRepository().isStandardDescriptor(key); } @@ -479,7 +517,10 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { return getRepository().getDescriptorValues(key); } - // BEANS METHODS + /* + * FIELDS ACCESS + */ + public void setHomeDirectory(File homeDirectory) { this.homeDirectory = homeDirectory; } @@ -508,6 +549,10 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { this.uri = uri; } + public void setRemoteSystemCredentials(Credentials remoteSystemCredentials) { + this.remoteSystemCredentials = remoteSystemCredentials; + } + public void setSystemExecutor(Executor systemExecutor) { this.systemExecutor = systemExecutor; } @@ -520,5 +565,4 @@ public class JackrabbitContainer implements Repository, ResourceLoaderAware { Set dataModelMigrations) { this.dataModelMigrations = dataModelMigrations; } - }