X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms.jcr%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fjcr%2FRepositoryBuilder.java;fp=org.argeo.cms.jcr%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fjcr%2FRepositoryBuilder.java;h=3db97167c3dae6947996372d818f8d74004f4f1c;hb=bce03099b0d2f1758e7a3d74fba339d0200924d5;hp=0000000000000000000000000000000000000000;hpb=0ea2992e5f3803cd98b5981f27274faa922bc199;p=gpl%2Fargeo-jcr.git diff --git a/org.argeo.cms.jcr/src/org/argeo/cms/internal/jcr/RepositoryBuilder.java b/org.argeo.cms.jcr/src/org/argeo/cms/internal/jcr/RepositoryBuilder.java new file mode 100644 index 0000000..3db9716 --- /dev/null +++ b/org.argeo.cms.jcr/src/org/argeo/cms/internal/jcr/RepositoryBuilder.java @@ -0,0 +1,225 @@ +package org.argeo.cms.internal.jcr; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.Properties; +import java.util.UUID; + +import javax.jcr.RepositoryException; + +import org.apache.jackrabbit.core.RepositoryContext; +import org.apache.jackrabbit.core.RepositoryImpl; +import org.apache.jackrabbit.core.cache.CacheManager; +import org.apache.jackrabbit.core.config.RepositoryConfig; +import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; +import org.argeo.api.cms.CmsConstants; +import org.argeo.api.cms.CmsLog; +import org.argeo.cms.jcr.internal.CmsPaths; +import org.xml.sax.InputSource; + +/** Can interpret properties in order to create an actual JCR repository. */ +public class RepositoryBuilder { + private final static CmsLog log = CmsLog.getLog(RepositoryBuilder.class); + + public RepositoryContext createRepositoryContext(Dictionary properties) + throws RepositoryException, IOException { + RepositoryConfig repositoryConfig = createRepositoryConfig(properties); + RepositoryContext repositoryContext = createJackrabbitRepository(repositoryConfig); + RepositoryImpl repository = repositoryContext.getRepository(); + + // cache + Object maxCacheMbStr = prop(properties, RepoConf.maxCacheMB); + if (maxCacheMbStr != null) { + Integer maxCacheMB = Integer.parseInt(maxCacheMbStr.toString()); + CacheManager cacheManager = repository.getCacheManager(); + cacheManager.setMaxMemory(maxCacheMB * 1024l * 1024l); + cacheManager.setMaxMemoryPerCache((maxCacheMB / 4) * 1024l * 1024l); + } + + return repositoryContext; + } + + RepositoryConfig createRepositoryConfig(Dictionary properties) throws RepositoryException, IOException { + JackrabbitType type = JackrabbitType.valueOf(prop(properties, RepoConf.type).toString()); + ClassLoader cl = getClass().getClassLoader(); + final String base = "/org/argeo/cms/internal/jcr"; + try (InputStream in = cl.getResourceAsStream(base + "/repository-" + type.name() + ".xml")) { + if (in == null) + throw new IllegalArgumentException("Repository configuration not found"); + InputSource config = new InputSource(in); + Properties jackrabbitVars = getConfigurationProperties(type, properties); + // RepositoryConfig repositoryConfig = RepositoryConfig.create(config, + // jackrabbitVars); + + // custom configuration parser + CustomRepositoryConfigurationParser parser = new CustomRepositoryConfigurationParser(jackrabbitVars); + parser.setClassLoader(cl); + RepositoryConfig repositoryConfig = parser.parseRepositoryConfig(config); + repositoryConfig.init(); + + // set the proper classloaders + repositoryConfig.getSecurityConfig().getSecurityManagerConfig().setClassLoader(cl); + repositoryConfig.getSecurityConfig().getAccessManagerConfig().setClassLoader(cl); +// for (WorkspaceConfig workspaceConfig : repositoryConfig.getWorkspaceConfigs()) { +// workspaceConfig.getSecurityConfig().getAccessControlProviderConfig().setClassLoader(cl); +// } + return repositoryConfig; + } + } + + private Properties getConfigurationProperties(JackrabbitType type, Dictionary properties) { + Properties props = new Properties(); + for (Enumeration keys = properties.keys(); keys.hasMoreElements();) { + String key = keys.nextElement(); + props.put(key, properties.get(key)); + } + + // cluster id + // cf. https://wiki.apache.org/jackrabbit/Clustering + // TODO deal with multiple repos + String clusterId = System.getProperty("org.apache.jackrabbit.core.cluster.node_id"); + String clusterIdProp = props.getProperty(RepoConf.clusterId.name()); + if (clusterId != null) { + if (clusterIdProp != null) + throw new IllegalArgumentException("Cluster id defined as System properties and in deploy config"); + props.put(RepoConf.clusterId.name(), clusterId); + } else { + clusterId = clusterIdProp; + } + + // home + String homeUri = props.getProperty(RepoConf.labeledUri.name()); + Path homePath; + if (homeUri == null) { + String cn = props.getProperty(CmsConstants.CN); + assert cn != null; + if (clusterId != null) { + homePath = CmsPaths.getRepoDirPath(cn + '/' + clusterId); + } else { + homePath = CmsPaths.getRepoDirPath(cn); + } + } else { + try { + URI uri = new URI(homeUri); + String host = uri.getHost(); + if (host == null || host.trim().equals("")) { + homePath = Paths.get(uri).toAbsolutePath(); + } else { + // TODO remote at this stage? + throw new IllegalArgumentException("Cannot manage repository path for host " + host); + } + } catch (URISyntaxException e) { + throw new IllegalArgumentException("Invalid repository home URI", e); + } + } + // TODO use Jackrabbit API (?) + Path rootUuidPath = homePath.resolve("repository/meta/rootUUID"); + try { + if (!Files.exists(rootUuidPath)) { + Files.createDirectories(rootUuidPath.getParent()); + Files.write(rootUuidPath, UUID.randomUUID().toString().getBytes()); + } + // File homeDir = homePath.toFile(); + // homeDir.mkdirs(); + } catch (IOException e) { + throw new RuntimeException("Cannot set up repository home " + homePath, e); + } + // home cannot be overridden + props.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, homePath.toString()); + + setProp(props, RepoConf.indexesBase, CmsPaths.getRepoIndexesBase().toString()); + // common + setProp(props, RepoConf.defaultWorkspace); + setProp(props, RepoConf.maxPoolSize); + // Jackrabbit defaults + setProp(props, RepoConf.bundleCacheMB); + // See http://wiki.apache.org/jackrabbit/Search + setProp(props, RepoConf.extractorPoolSize); + setProp(props, RepoConf.searchCacheSize); + setProp(props, RepoConf.maxVolatileIndexSize); + + // specific + String dburl; + switch (type) { + case h2: + dburl = "jdbc:h2:" + homePath.toAbsolutePath() + "/h2/repository"; + setProp(props, RepoConf.dburl, dburl); + setProp(props, RepoConf.dbuser, "sa"); + setProp(props, RepoConf.dbpassword, ""); + break; + case h2_postgresql: + dburl = "jdbc:h2:" + homePath.toAbsolutePath() + "/h2/repository;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE"; + setProp(props, RepoConf.dburl, dburl); + setProp(props, RepoConf.dbuser, "sa"); + setProp(props, RepoConf.dbpassword, ""); + break; + case postgresql: + case postgresql_ds: + case postgresql_cluster: + case postgresql_cluster_ds: + dburl = "jdbc:postgresql://localhost/demo"; + setProp(props, RepoConf.dburl, dburl); + setProp(props, RepoConf.dbuser, "argeo"); + setProp(props, RepoConf.dbpassword, "argeo"); + break; + case memory: + break; + case localfs: + break; + default: + throw new IllegalArgumentException("Unsupported node type " + type); + } + return props; + } + + private void setProp(Properties props, RepoConf key, String def) { + Object value = props.get(key.name()); + if (value == null) + value = def; + if (value == null) + value = key.getDefault(); + if (value != null) + props.put(key.name(), value.toString()); + } + + private void setProp(Properties props, RepoConf key) { + setProp(props, key, null); + } + + private String prop(Dictionary properties, RepoConf key) { + Object value = properties.get(key.name()); + if (value == null) + return key.getDefault() != null ? key.getDefault().toString() : null; + else + return value.toString(); + } + + private RepositoryContext createJackrabbitRepository(RepositoryConfig repositoryConfig) throws RepositoryException { + ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(RepositoryBuilder.class.getClassLoader()); + try { + long begin = System.currentTimeMillis(); + // + // Actual repository creation + // + RepositoryContext repositoryContext = RepositoryContext.create(repositoryConfig); + + double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; + if (log.isDebugEnabled()) + log.debug( + "Created Jackrabbit repository in " + duration + " s, home: " + repositoryConfig.getHomeDir()); + + return repositoryContext; + } finally { + Thread.currentThread().setContextClassLoader(currentContextCl); + } + } + +}