Use OSGi Configuration Manager for node's Jackrabbit repository
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 6 Apr 2016 14:35:56 +0000 (14:35 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 6 Apr 2016 14:35:56 +0000 (14:35 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@8861 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

19 files changed:
demo/argeo_node_rap.properties
org.argeo.cms/src/org/argeo/cms/CmsExtension.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelThread.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeRepository.java
org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitDataModel.java [new file with mode: 0644]
org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitNodeType.java [new file with mode: 0644]
org.argeo.server.jcr/src/org/argeo/jackrabbit/ManagedJackrabbitRepository.java [new file with mode: 0644]
org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-fs.xml [deleted file]
org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-h2.xml
org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-localfs.xml [new file with mode: 0644]
org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-memory.xml
org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-postgresql-ds.xml [new file with mode: 0644]
org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-postgresql.xml [new file with mode: 0644]
org.argeo.server.jcr/src/org/argeo/jcr/ArgeoJcrConstants.java
org.argeo.server.jcr/src/org/argeo/jcr/ArgeoJcrException.java [new file with mode: 0644]
org.argeo.server.jcr/src/org/argeo/jcr/RepoConf.java [new file with mode: 0644]

index b370cae088d554b2697810d2a1b805b0dfbbd4c5..f96484a0d623b1bf9e6c3fe9b8111e6b11324739 100644 (file)
@@ -1,6 +1,7 @@
 argeo.osgi.start.2.node=\
 org.eclipse.equinox.http.servlet,\
 org.eclipse.equinox.http.jetty,\
+org.eclipse.equinox.cm,\
 org.eclipse.rap.rwt.osgi
 
 argeo.osgi.start.3.node=\
diff --git a/org.argeo.cms/src/org/argeo/cms/CmsExtension.java b/org.argeo.cms/src/org/argeo/cms/CmsExtension.java
new file mode 100644 (file)
index 0000000..b574dc5
--- /dev/null
@@ -0,0 +1,19 @@
+package org.argeo.cms;
+
+import java.util.List;
+
+import javax.jcr.Session;
+
+public interface CmsExtension {
+       public List<String> getDataModels();
+
+       public List<String> getRoles();
+
+       public void onInit(Session adminSession);
+
+       public void onStart(Session adminSession);
+
+       public void onShutdown(Session adminSession);
+
+       public void onDestroy(Session adminSession);
+}
index 3960be687ff91a0ec56408b30d8a167d01b134a9..785c44716ea569c34707fd91dd943d00426ea5e1 100644 (file)
@@ -17,6 +17,7 @@ import java.io.FileFilter;
 import java.io.IOException;
 import java.lang.management.ManagementFactory;
 import java.security.PrivilegedAction;
+import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.List;
@@ -44,14 +45,18 @@ import org.argeo.ArgeoException;
 import org.argeo.ArgeoLogger;
 import org.argeo.cms.CmsException;
 import org.argeo.cms.maintenance.MaintenanceUi;
+import org.argeo.jackrabbit.JackrabbitDataModel;
+import org.argeo.jackrabbit.ManagedJackrabbitRepository;
 import org.argeo.jackrabbit.OsgiJackrabbitRepositoryFactory;
 import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.jcr.ArgeoJcrUtils;
+import org.argeo.jcr.RepoConf;
 import org.eclipse.equinox.http.jetty.JettyConfigurator;
 import org.eclipse.equinox.http.jetty.JettyConstants;
 import org.eclipse.equinox.http.servlet.ExtendedHttpService;
 import org.eclipse.rap.rwt.application.ApplicationConfiguration;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceEvent;
 import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServiceReference;
@@ -59,6 +64,7 @@ import org.osgi.framework.ServiceRegistration;
 import org.osgi.framework.startlevel.BundleStartLevel;
 import org.osgi.service.cm.Configuration;
 import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ManagedService;
 import org.osgi.service.log.LogReaderService;
 import org.osgi.service.useradmin.UserAdmin;
 import org.osgi.util.tracker.ServiceTracker;
@@ -101,7 +107,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
        private BitronixTransactionManager transactionManager;
        private BitronixTransactionSynchronizationRegistry transactionSynchronizationRegistry;
        private OsgiJackrabbitRepositoryFactory repositoryFactory;
-       NodeRepository repository;
+       JackrabbitRepository repository;
        private NodeUserAdmin userAdmin;
 
        // Members
@@ -122,29 +128,25 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
        }
 
        final void init() {
-               Subject.doAs(nodeSecurity.getKernelSubject(),
-                               new PrivilegedAction<Void>() {
-                                       @Override
-                                       public Void run() {
-                                               doInit();
-                                               return null;
-                                       }
-                               });
+               Subject.doAs(nodeSecurity.getKernelSubject(), new PrivilegedAction<Void>() {
+                       @Override
+                       public Void run() {
+                               doInit();
+                               return null;
+                       }
+               });
        }
 
        private void doInit() {
                long begin = System.currentTimeMillis();
                // Use CMS bundle classloader
-               ClassLoader currentContextCl = Thread.currentThread()
-                               .getContextClassLoader();
-               Thread.currentThread().setContextClassLoader(
-                               Kernel.class.getClassLoader());
+               ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader();
+               Thread.currentThread().setContextClassLoader(Kernel.class.getClassLoader());
                try {
                        if (nodeSecurity.isFirstInit())
                                firstInit();
 
-                       defaultLocale = new Locale(getFrameworkProp(I18N_DEFAULT_LOCALE,
-                                       ENGLISH.getLanguage()));
+                       defaultLocale = new Locale(getFrameworkProp(I18N_DEFAULT_LOCALE, ENGLISH.getLanguage()));
                        locales = asLocaleList(getFrameworkProp(I18N_LOCALES));
 
                        ServiceTracker<LogReaderService, LogReaderService> logReaderService = new ServiceTracker<LogReaderService, LogReaderService>(
@@ -164,16 +166,14 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                        Thread.currentThread().setContextClassLoader(currentContextCl);
                        // FIXME better manage lifecycle.
                        try {
-                               new LoginContext(LOGIN_CONTEXT_KERNEL,
-                                               nodeSecurity.getKernelSubject()).logout();
+                               new LoginContext(LOGIN_CONTEXT_KERNEL, nodeSecurity.getKernelSubject()).logout();
                        } catch (LoginException e) {
                                e.printStackTrace();
                        }
                }
 
                long jvmUptime = ManagementFactory.getRuntimeMXBean().getUptime();
-               log.info("## ARGEO CMS UP in " + (jvmUptime / 1000) + "."
-                               + (jvmUptime % 1000) + "s ##");
+               log.info("## ARGEO CMS UP in " + (jvmUptime / 1000) + "." + (jvmUptime % 1000) + "s ##");
                long initDuration = System.currentTimeMillis() - begin;
                if (log.isTraceEnabled())
                        log.trace("Kernel initialization took " + initDuration + "ms");
@@ -182,21 +182,46 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
 
        private void normalInit() {
                ConfigurationAdmin conf = findConfigurationAdmin();
+
+               // HTTP
+               initWebServer(conf);
+               ServiceReference<ExtendedHttpService> sr = bc.getServiceReference(ExtendedHttpService.class);
+               if (sr != null)
+                       addHttpService(sr);
+
                // Initialise services
                initTransactionManager();
+
+               try {
+                       Configuration nodeConf = conf.getConfiguration(ArgeoJcrConstants.REPO_PID_NODE);
+                       if (nodeConf.getProperties() == null) {
+                               Dictionary<String, ?> props = getNodeConfigFromFrameworkProperties();
+                               if(props==null)// TODO interactive configuration
+                                       return;
+                               nodeConf.update(props);
+                       }
+               } catch (IOException e) {
+                       throw new CmsException("Cannot get configuration", e);
+               }
+
+               ManagedJackrabbitRepository nodeRepo = new ManagedJackrabbitRepository();
+               String[] clazzes = { ManagedService.class.getName(), Repository.class.getName(),
+                               JackrabbitRepository.class.getName() };
+               Hashtable<String, String> serviceProps = new Hashtable<String, String>();
+               serviceProps.put(Constants.SERVICE_PID, ArgeoJcrConstants.REPO_PID_NODE);
+               serviceProps.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, ArgeoJcrConstants.ALIAS_NODE);
+               ServiceRegistration<?> nodeSr = bc.registerService(clazzes, nodeRepo, serviceProps);
+               nodeRepo.waitForInit();
+               new JackrabbitDataModel(bc).prepareDataModel(nodeRepo);
+
+               repository = (JackrabbitRepository) bc.getService(nodeSr.getReference());
+
                if (repository == null)
                        repository = new NodeRepository();
                if (repositoryFactory == null)
                        repositoryFactory = new OsgiJackrabbitRepositoryFactory();
                userAdmin = new NodeUserAdmin(transactionManager, repository);
 
-               // HTTP
-               initWebServer(conf);
-               ServiceReference<ExtendedHttpService> sr = bc
-                               .getServiceReference(ExtendedHttpService.class);
-               if (sr != null)
-                       addHttpService(sr);
-
                // ADMIN UIs
                UserUi userUi = new UserUi();
                Hashtable<String, String> props = new Hashtable<String, String>();
@@ -212,12 +237,26 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                publish();
        }
 
+       private Dictionary<String, ?> getNodeConfigFromFrameworkProperties() {
+               String repoType = KernelUtils
+                               .getFrameworkProp(KernelConstants.NODE_REPO_PROP_PREFIX + RepoConf.type.name());
+               if (repoType == null)
+                       return null;
+               
+               Hashtable<String, Object> props = new Hashtable<String, Object>();
+               for (RepoConf repoConf : RepoConf.values()) {
+                       String value = KernelUtils.getFrameworkProp(KernelConstants.NODE_REPO_PROP_PREFIX + repoConf.name());
+                       if (value != null)
+                               props.put(repoConf.name(), value);
+               }
+               return props;
+       }
+
        private boolean isMaintenance() {
                String startLevel = KernelUtils.getFrameworkProp("osgi.startLevel");
                if (startLevel == null)
                        return false;
-               int bundleStartLevel = bc.getBundle().adapt(BundleStartLevel.class)
-                               .getStartLevel();
+               int bundleStartLevel = bc.getBundle().adapt(BundleStartLevel.class).getStartLevel();
                // int frameworkStartLevel =
                // bc.getBundle(0).adapt(BundleStartLevel.class)
                // .getStartLevel();
@@ -254,17 +293,15 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                // TODO also uncompress archives
                if (initDir.exists())
                        try {
-                               FileUtils.copyDirectory(initDir, getOsgiInstanceDir(),
-                                               new FileFilter() {
-
-                                                       @Override
-                                                       public boolean accept(File pathname) {
-                                                               if (pathname.getName().equals(".svn")
-                                                                               || pathname.getName().equals(".git"))
-                                                                       return false;
-                                                               return true;
-                                                       }
-                                               });
+                               FileUtils.copyDirectory(initDir, getOsgiInstanceDir(), new FileFilter() {
+
+                                       @Override
+                                       public boolean accept(File pathname) {
+                                               if (pathname.getName().equals(".svn") || pathname.getName().equals(".git"))
+                                                       return false;
+                                               return true;
+                                       }
+                               });
                                log.info("CMS initialized from " + initDir.getCanonicalPath());
                        } catch (IOException e) {
                                throw new CmsException("Cannot initialize from " + initDir, e);
@@ -275,21 +312,16 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                try {
                        repository = new NodeRepository();
                        repositoryFactory = new OsgiJackrabbitRepositoryFactory();
-                       Repository remoteRepository = ArgeoJcrUtils.getRepositoryByUri(
-                                       repositoryFactory, uri);
-                       Session remoteSession = remoteRepository
-                                       .login(new SimpleCredentials("root", "demo".toCharArray()),
-                                                       "main");
+                       Repository remoteRepository = ArgeoJcrUtils.getRepositoryByUri(repositoryFactory, uri);
+                       Session remoteSession = remoteRepository.login(new SimpleCredentials("root", "demo".toCharArray()), "main");
                        Session localSession = this.repository.login();
                        // FIXME register node type
                        // if (false)
                        // CndImporter.registerNodeTypes(null, localSession);
                        ByteArrayOutputStream out = new ByteArrayOutputStream();
                        remoteSession.exportSystemView("/", out, true, false);
-                       ByteArrayInputStream in = new ByteArrayInputStream(
-                                       out.toByteArray());
-                       localSession.importXML("/", in,
-                                       ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
+                       ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+                       localSession.importXML("/", in, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
                        // JcrUtils.copy(remoteSession.getRootNode(),
                        // localSession.getRootNode());
                } catch (Exception e) {
@@ -307,8 +339,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
        }
 
        private void initTransactionManager() {
-               bitronix.tm.Configuration tmConf = TransactionManagerServices
-                               .getConfiguration();
+               bitronix.tm.Configuration tmConf = TransactionManagerServices.getConfiguration();
                tmConf.setServerId(getFrameworkProp(FRAMEWORK_UUID));
 
                // File tmBaseDir = new File(getFrameworkProp(TRANSACTIONS_HOME,
@@ -316,12 +347,10 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                File tmBaseDir = bc.getDataFile(DIR_TRANSACTIONS);
                File tmDir1 = new File(tmBaseDir, "btm1");
                tmDir1.mkdirs();
-               tmConf.setLogPart1Filename(new File(tmDir1, tmDir1.getName() + ".tlog")
-                               .getAbsolutePath());
+               tmConf.setLogPart1Filename(new File(tmDir1, tmDir1.getName() + ".tlog").getAbsolutePath());
                File tmDir2 = new File(tmBaseDir, "btm2");
                tmDir2.mkdirs();
-               tmConf.setLogPart2Filename(new File(tmDir2, tmDir2.getName() + ".tlog")
-                               .getAbsolutePath());
+               tmConf.setLogPart2Filename(new File(tmDir2, tmDir2.getName() + ".tlog").getAbsolutePath());
                transactionManager = getTransactionManager();
                transactionSynchronizationRegistry = getTransactionSynchronizationRegistry();
        }
@@ -340,27 +369,24 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                                        jettyProps.put(JettyConstants.HTTPS_PORT, httpsPort);
                                        jettyProps.put(JettyConstants.HTTPS_ENABLED, true);
                                        jettyProps.put(JettyConstants.SSL_KEYSTORETYPE, "PKCS12");
-                                       jettyProps.put(JettyConstants.SSL_KEYSTORE, nodeSecurity
-                                                       .getHttpServerKeyStore().getCanonicalPath());
+                                       jettyProps.put(JettyConstants.SSL_KEYSTORE,
+                                                       nodeSecurity.getHttpServerKeyStore().getCanonicalPath());
                                        jettyProps.put(JettyConstants.SSL_PASSWORD, "changeit");
                                        jettyProps.put(JettyConstants.SSL_WANTCLIENTAUTH, true);
                                }
                                if (conf != null) {
                                        // TODO make filter more generic
-                                       String filter = "(" + JettyConstants.HTTP_PORT + "="
-                                                       + httpPort + ")";
+                                       String filter = "(" + JettyConstants.HTTP_PORT + "=" + httpPort + ")";
                                        if (conf.listConfigurations(filter) != null)
                                                return;
-                                       Configuration jettyConf = conf.createFactoryConfiguration(
-                                                       JETTY_FACTORY_PID, null);
+                                       Configuration jettyConf = conf.createFactoryConfiguration(JETTY_FACTORY_PID, null);
                                        jettyConf.update(jettyProps);
                                } else {
                                        JettyConfigurator.startServer("default", jettyProps);
                                }
                        }
                } catch (Exception e) {
-                       throw new CmsException("Cannot initialize web server on "
-                                       + httpPortsMsg(httpPort, httpsPort), e);
+                       throw new CmsException("Cannot initialize web server on " + httpPortsMsg(httpPort, httpsPort), e);
                }
        }
 
@@ -372,24 +398,18 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                // Logging
                loggerReg = bc.registerService(ArgeoLogger.class, logger, null);
                // Transaction
-               tmReg = bc.registerService(TransactionManager.class,
-                               transactionManager, null);
-               utReg = bc.registerService(UserTransaction.class, transactionManager,
-                               null);
-               tsrReg = bc.registerService(TransactionSynchronizationRegistry.class,
-                               transactionSynchronizationRegistry, null);
+               tmReg = bc.registerService(TransactionManager.class, transactionManager, null);
+               utReg = bc.registerService(UserTransaction.class, transactionManager, null);
+               tsrReg = bc.registerService(TransactionSynchronizationRegistry.class, transactionSynchronizationRegistry, null);
                // User admin
-               userAdminReg = bc.registerService(UserAdmin.class, userAdmin,
-                               userAdmin.currentState());
+               userAdminReg = bc.registerService(UserAdmin.class, userAdmin, userAdmin.currentState());
                // JCR
                Hashtable<String, String> regProps = new Hashtable<String, String>();
                regProps.put(JCR_REPOSITORY_ALIAS, ALIAS_NODE);
-               repositoryReg = (ServiceRegistration<? extends Repository>) bc
-                               .registerService(new String[] { Repository.class.getName(),
-                                               JackrabbitRepository.class.getName() }, repository,
-                                               regProps);
-               repositoryFactoryReg = bc.registerService(RepositoryFactory.class,
-                               repositoryFactory, null);
+               repositoryReg = (ServiceRegistration<? extends Repository>) bc.registerService(
+                               new String[] { Repository.class.getName(), JackrabbitRepository.class.getName() }, repository,
+                               regProps);
+               repositoryFactoryReg = bc.registerService(RepositoryFactory.class, repositoryFactory, null);
        }
 
        void destroy() {
@@ -405,7 +425,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                if (userAdmin != null)
                        userAdmin.destroy();
                if (repository != null)
-                       repository.destroy();
+                       repository.shutdown();
                if (transactionManager != null)
                        transactionManager.shutdown();
 
@@ -419,8 +439,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
 
                nodeSecurity.destroy();
                long duration = System.currentTimeMillis() - begin;
-               log.info("## ARGEO CMS DOWN in " + (duration / 1000) + "."
-                               + (duration % 1000) + "s ##");
+               log.info("## ARGEO CMS DOWN in " + (duration / 1000) + "." + (duration % 1000) + "s ##");
        }
 
        private void unpublish() {
@@ -438,8 +457,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                ServiceReference<?> sr = event.getServiceReference();
                Object service = bc.getService(sr);
                if (service instanceof Repository) {
-                       Object jcrRepoAlias = sr
-                                       .getProperty(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS);
+                       Object jcrRepoAlias = sr.getProperty(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS);
                        if (jcrRepoAlias != null) {// JCR repository
                                String alias = jcrRepoAlias.toString();
                                Repository repository = (Repository) bc.getService(sr);
@@ -451,8 +469,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                                                repositoryFactory.register(repository, props);
                                                dataHttp.registerRepositoryServlets(alias, repository);
                                        } catch (Exception e) {
-                                               throw new CmsException(
-                                                               "Could not publish JCR repository " + alias, e);
+                                               throw new CmsException("Could not publish JCR repository " + alias, e);
                                        }
                                } else if (ServiceEvent.UNREGISTERING == event.getType()) {
                                        repositoryFactory.unregister(repository, props);
@@ -472,8 +489,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
        private void addHttpService(ServiceReference<?> sr) {
                // for (String key : sr.getPropertyKeys())
                // log.debug(key + "=" + sr.getProperty(key));
-               ExtendedHttpService httpService = (ExtendedHttpService) bc
-                               .getService(sr);
+               ExtendedHttpService httpService = (ExtendedHttpService) bc.getService(sr);
                // TODO find constants
                Object httpPort = sr.getProperty("http.port");
                Object httpsPort = sr.getProperty("https.port");
@@ -484,8 +500,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
        }
 
        private String httpPortsMsg(Object httpPort, Object httpsPort) {
-               return "HTTP " + httpPort
-                               + (httpsPort != null ? " - HTTPS " + httpsPort : "");
+               return "HTTP " + httpPort + (httpsPort != null ? " - HTTPS " + httpsPort : "");
        }
 
        @Override
@@ -502,9 +517,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
        final private static void directorsCut(long initDuration) {
                // final long ms = 128l + (long) (Math.random() * 128d);
                long ms = initDuration / 100;
-               log.info("Spend " + ms + "ms"
-                               + " reflecting on the progress brought to mankind"
-                               + " by Free Software...");
+               log.info("Spend " + ms + "ms" + " reflecting on the progress brought to mankind" + " by Free Software...");
                long beginNano = System.nanoTime();
                try {
                        Thread.sleep(ms, 0);
@@ -515,9 +528,7 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                final double M = 1000d * 1000d;
                double sleepAccuracy = ((double) durationNano) / (ms * M);
                if (log.isDebugEnabled())
-                       log.debug("Sleep accuracy: "
-                                       + String.format("%.2f", 100 - (sleepAccuracy * 100 - 100))
-                                       + " %");
+                       log.debug("Sleep accuracy: " + String.format("%.2f", 100 - (sleepAccuracy * 100 - 100)) + " %");
        }
 
        /** Workaround for blocking Gogo shell by system shutdown. */
index f7feb3106f0057cc977a7d355b7b680c06009046..e06afa829fd45fcb39b900587a38dfc91f2a4680 100644 (file)
@@ -4,19 +4,26 @@ public interface KernelConstants {
        final static String NODE_INIT = "argeo.node.init";
 
        // Node
-       final static String REPO_HOME = "argeo.node.repo.home";
-       final static String REPO_TYPE = "argeo.node.repo.type";
+       /** Properties configuring the node repository */
+       final static String NODE_REPO_PROP_PREFIX = "argeo.node.repo.";
+       // final static String REPO_HOME = "argeo.node.repo.home";
+       // final static String REPO_TYPE = "argeo.node.repo.type";
        // final static String REPO_CONFIGURATION = "argeo.node.repo.configuration";
-       final static String REPO_DEFAULT_WORKSPACE = "argeo.node.repo.defaultWorkspace";
-       final static String REPO_DBURL = "argeo.node.repo.dburl";
-       final static String REPO_DBUSER = "argeo.node.repo.dbuser";
-       final static String REPO_DBPASSWORD = "argeo.node.repo.dbpassword";
-       final static String REPO_MAX_POOL_SIZE = "argeo.node.repo.maxPoolSize";
-       final static String REPO_MAX_CACHE_MB = "argeo.node.repo.maxCacheMB";
-       final static String REPO_BUNDLE_CACHE_MB = "argeo.node.repo.bundleCacheMB";
-       final static String REPO_EXTRACTOR_POOL_SIZE = "argeo.node.repo.extractorPoolSize";
-       final static String REPO_SEARCH_CACHE_SIZE = "argeo.node.repo.searchCacheSize";
-       final static String REPO_MAX_VOLATILE_INDEX_SIZE = "argeo.node.repo.maxVolatileIndexSize";
+       // final static String REPO_DEFAULT_WORKSPACE =
+       // "argeo.node.repo.defaultWorkspace";
+       // final static String REPO_DBURL = "argeo.node.repo.dburl";
+       // final static String REPO_DBUSER = "argeo.node.repo.dbuser";
+       // final static String REPO_DBPASSWORD = "argeo.node.repo.dbpassword";
+       // final static String REPO_MAX_POOL_SIZE = "argeo.node.repo.maxPoolSize";
+       // final static String REPO_MAX_CACHE_MB = "argeo.node.repo.maxCacheMB";
+       // final static String REPO_BUNDLE_CACHE_MB =
+       // "argeo.node.repo.bundleCacheMB";
+       // final static String REPO_EXTRACTOR_POOL_SIZE =
+       // "argeo.node.repo.extractorPoolSize";
+       // final static String REPO_SEARCH_CACHE_SIZE =
+       // "argeo.node.repo.searchCacheSize";
+       // final static String REPO_MAX_VOLATILE_INDEX_SIZE =
+       // "argeo.node.repo.maxVolatileIndexSize";
 
        final static String TRANSACTIONS_HOME = "argeo.node.transactions.home";
 
@@ -27,8 +34,7 @@ public interface KernelConstants {
        final static String ROLES_URI = "argeo.node.roles.uri";
        /** URI to an LDIF file or LDAP server used as initialization or backend */
        final static String USERADMIN_URIS = "argeo.node.useradmin.uris";
-       final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd",
-                       "/org/argeo/cms/cms.cnd" };
+       final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd", "/org/argeo/cms/cms.cnd" };
 
        // Directories
        final static String DIR_NODE = "node";
index 4b4b8026f983830d6e307b36d332ed9a9544e70a..228737b9d42721b64c5b56a7cb52d891f078303b 100644 (file)
@@ -16,7 +16,7 @@ import org.argeo.cms.CmsException;
 class KernelThread extends Thread {
        @SuppressWarnings("unused")
        private final Kernel kernel;
-       private final RepositoryStatisticsImpl repoStats;
+       private RepositoryStatisticsImpl repoStats;
 
        /** The smallest period of operation, in ms */
        private final long PERIOD = 60 * 1000l;
@@ -35,7 +35,7 @@ class KernelThread extends Thread {
        public KernelThread(Kernel kernel) {
                super(kernel.threadGroup, kernel.getClass().getSimpleName());
                this.kernel = kernel;
-               this.repoStats = kernel.repository.getRepositoryStatistics();
+               // this.repoStats = kernel.repository.getRepositoryStatistics();
        }
 
        private void doSmallestPeriod() {
@@ -45,19 +45,17 @@ class KernelThread extends Thread {
                        long freeMem = Runtime.getRuntime().freeMemory() / M;
                        long totalMem = Runtime.getRuntime().totalMemory() / M;
                        long maxMem = Runtime.getRuntime().maxMemory() / M;
-                       double loadAvg = ManagementFactory.getOperatingSystemMXBean()
-                                       .getSystemLoadAverage();
+                       double loadAvg = ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage();
                        // in min
                        boolean min = true;
-                       long uptime = ManagementFactory.getRuntimeMXBean().getUptime()
-                                       / (1000 * 60);
+                       long uptime = ManagementFactory.getRuntimeMXBean().getUptime() / (1000 * 60);
                        if (uptime > 24 * 60) {
                                min = false;
                                uptime = uptime / 60;
                        }
                        line.append(uptime).append(min ? " min" : " h").append('\t');
-                       line.append(loadAvg).append('\t').append(maxMem).append('\t')
-                                       .append(totalMem).append('\t').append(freeMem).append('\t');
+                       line.append(loadAvg).append('\t').append(maxMem).append('\t').append(totalMem).append('\t').append(freeMem)
+                                       .append('\t');
                        kernelStatsLog.debug(line);
                }
 
@@ -77,15 +75,14 @@ class KernelThread extends Thread {
                        // }
                        // long totalSpace = currentRoot.getTotalSpace();
                        StringBuilder line = new StringBuilder(128);
-                       line.append("§\t").append(freeSpace)
-                                       .append(" MB left in " + dataDir);
+                       line.append("§\t").append(freeSpace).append(" MB left in " + dataDir);
                        line.append('\n');
-                       for (RepositoryStatistics.Type type : RepositoryStatistics.Type
-                                       .values()) {
-                               long[] vals = repoStats.getTimeSeries(type).getValuePerMinute();
-                               long val = vals[vals.length - 1];
-                               line.append(type.name()).append('\t').append(val).append('\n');
-                       }
+                       if (repoStats != null)
+                               for (RepositoryStatistics.Type type : RepositoryStatistics.Type.values()) {
+                                       long[] vals = repoStats.getTimeSeries(type).getValuePerMinute();
+                                       long val = vals[vals.length - 1];
+                                       line.append(type.name()).append('\t').append(val).append('\n');
+                               }
                        nodeStatsLog.debug(line);
                }
        }
index 27083aeaba11812fd219ac60ab7e950ee3c01114..42f527943f49d06447a550cdba044a0b066de515 100644 (file)
@@ -48,7 +48,7 @@ class NodeHttp implements KernelConstants, ArgeoJcrConstants {
 
        private Repository repository;
 
-       NodeHttp(ExtendedHttpService httpService, NodeRepository node) {
+       NodeHttp(ExtendedHttpService httpService, Repository node) {
                this.repository = node;
                // rootFilter = new RootFilter();
                // dosFilter = new CustomDosFilter();
index 37ed7babb29a7db5715e1da2cf7677a0577bc975..06e156fd399b596eb6c02964103d0856aee4be49 100644 (file)
@@ -29,161 +29,161 @@ import org.xml.sax.InputSource;
 /** Jacrabbit based data layer */
 class NodeRepository extends JackrabbitWrapper implements KernelConstants,
                ArgeoJcrConstants {
-       private static Log log = LogFactory.getLog(NodeRepository.class);
-
-       private RepositoryContext repositoryContext;
-
-       public NodeRepository() {
-               setBundleContext(Activator.getBundleContext());
-               JackrabbitNodeType type = JackrabbitNodeType.valueOf(prop(REPO_TYPE,
-                               h2.name()));
-               try {
-                       repositoryContext = createNode(type);
-                       setCndFiles(Arrays.asList(DEFAULT_CNDS));
-                       prepareDataModel();
-               } catch (Exception e) {
-                       throw new ArgeoException(
-                                       "Cannot create Jackrabbit repository of type " + type, e);
-               }
-       }
-
-       public void destroy() {
-               ((RepositoryImpl) getRepository()).shutdown();
-       }
-
-       RepositoryStatisticsImpl getRepositoryStatistics() {
-               return repositoryContext.getRepositoryStatistics();
-       }
-
-       private RepositoryConfig getConfiguration(JackrabbitNodeType type,
-                       Hashtable<String, Object> vars) throws RepositoryException {
-               ClassLoader cl = getClass().getClassLoader();
-               InputStream in = null;
-               try {
-                       final String base = "/org/argeo/cms/internal/kernel";
-                       switch (type) {
-                       case h2:
-                               in = cl.getResourceAsStream(base + "/repository-h2.xml");
-                               break;
-                       case postgresql:
-                               in = cl.getResourceAsStream(base + "/repository-postgresql.xml");
-                               break;
-                       case memory:
-                               in = cl.getResourceAsStream(base + "/repository-memory.xml");
-                               break;
-                       case localfs:
-                               in = cl.getResourceAsStream(base + "/repository-localfs.xml");
-                               break;
-                       default:
-                               throw new CmsException("Unsupported node type " + type);
-                       }
-
-                       if (in == null)
-                               throw new CmsException("Repository configuration not found");
-                       InputSource config = new InputSource(in);
-                       Properties jackrabbitProps = new Properties();
-                       jackrabbitProps.putAll(vars);
-                       RepositoryConfig repositoryConfig = RepositoryConfig.create(config,
-                                       jackrabbitProps);
-                       return repositoryConfig;
-               } finally {
-                       IOUtils.closeQuietly(in);
-               }
-       }
-
-       private Hashtable<String, Object> getConfigurationProperties(
-                       JackrabbitNodeType type) {
-               // use Hashtable to ease integration with Properties
-               Hashtable<String, Object> defaults = new Hashtable<String, Object>();
-
-               // home
-               File osgiInstanceDir = KernelUtils.getOsgiInstanceDir();
-               File homeDir = new File(osgiInstanceDir, DIR_NODE);
-               // home cannot be overridden
-               defaults.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE,
-                               homeDir.getAbsolutePath());
-
-               // common
-               setProp(defaults, REPO_DEFAULT_WORKSPACE, "main");
-               setProp(defaults, REPO_MAX_POOL_SIZE, "10");
-               // Jackrabbit defaults
-               setProp(defaults, REPO_BUNDLE_CACHE_MB, "8");
-               // See http://wiki.apache.org/jackrabbit/Search
-               setProp(defaults, REPO_EXTRACTOR_POOL_SIZE, "0");
-               setProp(defaults, REPO_SEARCH_CACHE_SIZE, "1000");
-               setProp(defaults, REPO_MAX_VOLATILE_INDEX_SIZE, "1048576");
-
-               // specific
-               String dburl;
-               switch (type) {
-               case h2:
-                       dburl = "jdbc:h2:" + homeDir.getPath() + "/h2/repository";
-                       setProp(defaults, REPO_DBURL, dburl);
-                       setProp(defaults, REPO_DBUSER, "sa");
-                       setProp(defaults, REPO_DBPASSWORD, "");
-                       break;
-               case postgresql:
-                       dburl = "jdbc:postgresql://localhost/demo";
-                       setProp(defaults, REPO_DBURL, dburl);
-                       setProp(defaults, REPO_DBUSER, "argeo");
-                       setProp(defaults, REPO_DBPASSWORD, "argeo");
-                       break;
-               case memory:
-                       break;
-               case localfs:
-                       break;
-               default:
-                       throw new CmsException("Unsupported node type " + type);
-               }
-               return defaults;
-       }
-
-       private void setProp(Dictionary<String, Object> props, String key,
-                       String defaultValue) {
-               String value = prop(key, defaultValue);
-               props.put(key, value);
-       }
-
-       private String prop(String key, String defaultValue) {
-               // TODO use OSGi CM instead of Framework/System properties
-               return KernelUtils.getFrameworkProp(key, defaultValue);
-       }
-
-       private RepositoryContext createNode(JackrabbitNodeType type)
-                       throws RepositoryException {
-               Hashtable<String, Object> vars = getConfigurationProperties(type);
-               RepositoryConfig repositoryConfig = getConfiguration(type, vars);
-               RepositoryContext repositoryContext = createJackrabbitRepository(repositoryConfig);
-               RepositoryImpl repository = repositoryContext.getRepository();
-
-               // cache
-               String maxCacheMbStr = prop(REPO_MAX_CACHE_MB, null);
-               if (maxCacheMbStr != null) {
-                       Integer maxCacheMB = Integer.parseInt(maxCacheMbStr);
-                       CacheManager cacheManager = repository.getCacheManager();
-                       cacheManager.setMaxMemory(maxCacheMB * 1024l * 1024l);
-                       cacheManager.setMaxMemoryPerCache((maxCacheMB / 4) * 1024l * 1024l);
-               }
-
-               // wrap the repository
-               setRepository(repository);
-               return repositoryContext;
-       }
-
-       private RepositoryContext createJackrabbitRepository(
-                       RepositoryConfig repositoryConfig) throws RepositoryException {
-               long begin = System.currentTimeMillis();
-               //
-               // Actual repository creation
-               //
-               RepositoryContext repositoryContext = RepositoryContext
-                               .create(repositoryConfig);
-
-               double duration = ((double) (System.currentTimeMillis() - begin)) / 1000;
-               if (log.isTraceEnabled())
-                       log.trace("Created Jackrabbit repository in " + duration
-                                       + " s, home: " + repositoryConfig.getHomeDir());
-
-               return repositoryContext;
-       }
+//     private static Log log = LogFactory.getLog(NodeRepository.class);
+//
+//     private RepositoryContext repositoryContext;
+//
+//     public NodeRepository() {
+//             setBundleContext(Activator.getBundleContext());
+//             JackrabbitNodeType type = JackrabbitNodeType.valueOf(prop(REPO_TYPE,
+//                             h2.name()));
+//             try {
+//                     repositoryContext = createNode(type);
+//                     setCndFiles(Arrays.asList(DEFAULT_CNDS));
+//                     prepareDataModel();
+//             } catch (Exception e) {
+//                     throw new ArgeoException(
+//                                     "Cannot create Jackrabbit repository of type " + type, e);
+//             }
+//     }
+//
+//     public void destroy() {
+//             ((RepositoryImpl) getRepository()).shutdown();
+//     }
+//
+//     RepositoryStatisticsImpl getRepositoryStatistics() {
+//             return repositoryContext.getRepositoryStatistics();
+//     }
+//
+//     private RepositoryConfig getConfiguration(JackrabbitNodeType type,
+//                     Hashtable<String, Object> vars) throws RepositoryException {
+//             ClassLoader cl = getClass().getClassLoader();
+//             InputStream in = null;
+//             try {
+//                     final String base = "/org/argeo/cms/internal/kernel";
+//                     switch (type) {
+//                     case h2:
+//                             in = cl.getResourceAsStream(base + "/repository-h2.xml");
+//                             break;
+//                     case postgresql:
+//                             in = cl.getResourceAsStream(base + "/repository-postgresql.xml");
+//                             break;
+//                     case memory:
+//                             in = cl.getResourceAsStream(base + "/repository-memory.xml");
+//                             break;
+//                     case localfs:
+//                             in = cl.getResourceAsStream(base + "/repository-localfs.xml");
+//                             break;
+//                     default:
+//                             throw new CmsException("Unsupported node type " + type);
+//                     }
+//
+//                     if (in == null)
+//                             throw new CmsException("Repository configuration not found");
+//                     InputSource config = new InputSource(in);
+//                     Properties jackrabbitProps = new Properties();
+//                     jackrabbitProps.putAll(vars);
+//                     RepositoryConfig repositoryConfig = RepositoryConfig.create(config,
+//                                     jackrabbitProps);
+//                     return repositoryConfig;
+//             } finally {
+//                     IOUtils.closeQuietly(in);
+//             }
+//     }
+//
+//     private Hashtable<String, Object> getConfigurationProperties(
+//                     JackrabbitNodeType type) {
+//             // use Hashtable to ease integration with Properties
+//             Hashtable<String, Object> defaults = new Hashtable<String, Object>();
+//
+//             // home
+//             File osgiInstanceDir = KernelUtils.getOsgiInstanceDir();
+//             File homeDir = new File(osgiInstanceDir, DIR_NODE);
+//             // home cannot be overridden
+//             defaults.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE,
+//                             homeDir.getAbsolutePath());
+//
+//             // common
+//             setProp(defaults, REPO_DEFAULT_WORKSPACE, "main");
+//             setProp(defaults, REPO_MAX_POOL_SIZE, "10");
+//             // Jackrabbit defaults
+//             setProp(defaults, REPO_BUNDLE_CACHE_MB, "8");
+//             // See http://wiki.apache.org/jackrabbit/Search
+//             setProp(defaults, REPO_EXTRACTOR_POOL_SIZE, "0");
+//             setProp(defaults, REPO_SEARCH_CACHE_SIZE, "1000");
+//             setProp(defaults, REPO_MAX_VOLATILE_INDEX_SIZE, "1048576");
+//
+//             // specific
+//             String dburl;
+//             switch (type) {
+//             case h2:
+//                     dburl = "jdbc:h2:" + homeDir.getPath() + "/h2/repository";
+//                     setProp(defaults, REPO_DBURL, dburl);
+//                     setProp(defaults, REPO_DBUSER, "sa");
+//                     setProp(defaults, REPO_DBPASSWORD, "");
+//                     break;
+//             case postgresql:
+//                     dburl = "jdbc:postgresql://localhost/demo";
+//                     setProp(defaults, REPO_DBURL, dburl);
+//                     setProp(defaults, REPO_DBUSER, "argeo");
+//                     setProp(defaults, REPO_DBPASSWORD, "argeo");
+//                     break;
+//             case memory:
+//                     break;
+//             case localfs:
+//                     break;
+//             default:
+//                     throw new CmsException("Unsupported node type " + type);
+//             }
+//             return defaults;
+//     }
+//
+//     private void setProp(Dictionary<String, Object> props, String key,
+//                     String defaultValue) {
+//             String value = prop(key, defaultValue);
+//             props.put(key, value);
+//     }
+//
+//     private String prop(String key, String defaultValue) {
+//             // TODO use OSGi CM instead of Framework/System properties
+//             return KernelUtils.getFrameworkProp(key, defaultValue);
+//     }
+//
+//     private RepositoryContext createNode(JackrabbitNodeType type)
+//                     throws RepositoryException {
+//             Hashtable<String, Object> vars = getConfigurationProperties(type);
+//             RepositoryConfig repositoryConfig = getConfiguration(type, vars);
+//             RepositoryContext repositoryContext = createJackrabbitRepository(repositoryConfig);
+//             RepositoryImpl repository = repositoryContext.getRepository();
+//
+//             // cache
+//             String maxCacheMbStr = prop(REPO_MAX_CACHE_MB, null);
+//             if (maxCacheMbStr != null) {
+//                     Integer maxCacheMB = Integer.parseInt(maxCacheMbStr);
+//                     CacheManager cacheManager = repository.getCacheManager();
+//                     cacheManager.setMaxMemory(maxCacheMB * 1024l * 1024l);
+//                     cacheManager.setMaxMemoryPerCache((maxCacheMB / 4) * 1024l * 1024l);
+//             }
+//
+//             // wrap the repository
+//             setRepository(repository);
+//             return repositoryContext;
+//     }
+//
+//     private RepositoryContext createJackrabbitRepository(
+//                     RepositoryConfig repositoryConfig) throws RepositoryException {
+//             long begin = System.currentTimeMillis();
+//             //
+//             // Actual repository creation
+//             //
+//             RepositoryContext repositoryContext = RepositoryContext
+//                             .create(repositoryConfig);
+//
+//             double duration = ((double) (System.currentTimeMillis() - begin)) / 1000;
+//             if (log.isTraceEnabled())
+//                     log.trace("Created Jackrabbit repository in " + duration
+//                                     + " s, home: " + repositoryConfig.getHomeDir());
+//
+//             return repositoryContext;
+//     }
 }
diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitDataModel.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitDataModel.java
new file mode 100644 (file)
index 0000000..b342d18
--- /dev/null
@@ -0,0 +1,283 @@
+package org.argeo.jackrabbit;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Repository;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.commons.NamespaceHelper;
+import org.apache.jackrabbit.commons.cnd.CndImporter;
+import org.argeo.ArgeoException;
+import org.argeo.jcr.ArgeoJcrConstants;
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.ArgeoTypes;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.util.security.DigestUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+public class JackrabbitDataModel {
+       private final static Log log = LogFactory.getLog(JackrabbitDataModel.class);
+       private final static String DIGEST_ALGORITHM = "MD5";
+       final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd", "/org/argeo/cms/cms.cnd" };
+
+       // data model
+       /** Node type definitions in CND format */
+       private List<String> cndFiles = new ArrayList<String>();
+       /**
+        * Always import CNDs. Useful during development of new data models. In
+        * production, explicit migration processes should be used.
+        */
+       private Boolean forceCndImport = true;
+
+       /** Namespaces to register: key is prefix, value namespace */
+       private Map<String, String> namespaces = new HashMap<String, String>();
+
+       private final BundleContext bc;
+
+       public JackrabbitDataModel(BundleContext bc) {
+               this.bc = bc;
+       }
+
+       /**
+        * 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.
+        */
+       public void prepareDataModel(Repository repository) {
+               cndFiles = Arrays.asList(DEFAULT_CNDS);
+               if ((cndFiles == null || cndFiles.size() == 0) && (namespaces == null || namespaces.size() == 0))
+                       return;
+
+               Session session = null;
+               try {
+                       session = repository.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) {
+                               processCndFile(session, resUrl);
+                       }
+               } catch (Exception e) {
+                       JcrUtils.discardQuietly(session);
+                       throw new ArgeoException("Cannot import node type definitions " + cndFiles, e);
+               } finally {
+                       JcrUtils.logoutQuietly(session);
+               }
+
+       }
+
+       protected void processCndFile(Session session, String resUrl) {
+               Reader reader = null;
+               try {
+                       // check existing data model nodes
+                       new NamespaceHelper(session).registerNamespace(ArgeoNames.ARGEO, ArgeoNames.ARGEO_NAMESPACE);
+                       if (!session.itemExists(ArgeoJcrConstants.DATA_MODELS_BASE_PATH))
+                               JcrUtils.mkdirs(session, ArgeoJcrConstants.DATA_MODELS_BASE_PATH);
+                       Node dataModels = session.getNode(ArgeoJcrConstants.DATA_MODELS_BASE_PATH);
+                       NodeIterator it = dataModels.getNodes();
+                       Node dataModel = null;
+                       while (it.hasNext()) {
+                               Node node = it.nextNode();
+                               if (node.getProperty(ArgeoNames.ARGEO_URI).getString().equals(resUrl)) {
+                                       dataModel = node;
+                                       break;
+                               }
+                       }
+
+                       Bundle bundle = findDataModelBundle(resUrl);
+
+                       byte[] cndContent = readCndContent(resUrl);
+                       String newDigest = DigestUtils.digest(DIGEST_ALGORITHM, cndContent);
+
+                       String currentVersion = null;
+                       if (dataModel != null) {
+                               currentVersion = dataModel.getProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION).getString();
+                               if (dataModel.hasNode(Node.JCR_CONTENT)) {
+                                       String oldDigest = JcrUtils.checksumFile(dataModel, DIGEST_ALGORITHM);
+                                       if (oldDigest.equals(newDigest)) {
+                                               if (log.isTraceEnabled())
+                                                       log.trace("Data model " + resUrl + " hasn't changed, keeping version " + currentVersion);
+                                               return;
+                                       }
+                               }
+                       }
+
+                       if (dataModel != null && !forceCndImport) {
+                               log.info(
+                                               "Data model " + resUrl + " has changed since version " + currentVersion
+                                                               + (bundle != null
+                                                                               ? ": version " + bundle.getVersion() + ", bundle " + bundle.getSymbolicName()
+                                                                               : ""));
+                               return;
+                       }
+
+                       reader = new InputStreamReader(new ByteArrayInputStream(cndContent));
+                       // actually imports the CND
+                       try {
+                               CndImporter.registerNodeTypes(reader, session, true);
+                       } catch (Exception e) {
+                               log.error("Cannot import data model " + resUrl, e);
+                               return;
+                       }
+
+                       if (dataModel != null && !dataModel.isNodeType(NodeType.NT_FILE)) {
+                               dataModel.remove();
+                               dataModel = null;
+                       }
+
+                       // FIXME: what if argeo.cnd would not be the first called on
+                       // a new repo? argeo:dataModel would not be found
+                       String fileName = FilenameUtils.getName(resUrl);
+                       if (dataModel == null) {
+                               dataModel = dataModels.addNode(fileName, NodeType.NT_FILE);
+                               dataModel.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE);
+                               dataModel.addMixin(ArgeoTypes.ARGEO_DATA_MODEL);
+                               dataModel.setProperty(ArgeoNames.ARGEO_URI, resUrl);
+                       } else {
+                               session.getWorkspace().getVersionManager().checkout(dataModel.getPath());
+                       }
+                       if (bundle != null)
+                               dataModel.setProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION, bundle.getVersion().toString());
+                       else
+                               dataModel.setProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION, "0.0.0");
+                       JcrUtils.copyBytesAsFile(dataModel.getParent(), fileName, cndContent);
+                       JcrUtils.updateLastModified(dataModel);
+                       session.save();
+                       session.getWorkspace().getVersionManager().checkin(dataModel.getPath());
+
+                       if (currentVersion == null)
+                               log.info(
+                                               "Data model " + resUrl
+                                                               + (bundle != null
+                                                                               ? ", version " + bundle.getVersion() + ", bundle " + bundle.getSymbolicName()
+                                                                               : ""));
+                       else
+                               log.info(
+                                               "Data model " + resUrl + " updated from version " + currentVersion
+                                                               + (bundle != null
+                                                                               ? ", version " + bundle.getVersion() + ", bundle " + bundle.getSymbolicName()
+                                                                               : ""));
+               } catch (Exception e) {
+                       throw new ArgeoException("Cannot process data model " + resUrl, e);
+               } finally {
+                       IOUtils.closeQuietly(reader);
+               }
+       }
+
+       protected byte[] readCndContent(String resUrl) {
+               BundleContext bundleContext = bc;
+               InputStream in = null;
+               try {
+                       boolean classpath;
+                       // normalize URL
+                       if (bundleContext != null && resUrl.startsWith("classpath:")) {
+                               resUrl = resUrl.substring("classpath:".length());
+                               classpath = true;
+                       } else if (resUrl.indexOf(':') < 0) {
+                               if (!resUrl.startsWith("/")) {
+                                       resUrl = "/" + resUrl;
+                                       log.warn("Classpath should start with '/'");
+                               }
+                               classpath = true;
+                       } else {
+                               classpath = false;
+                       }
+
+                       URL url = null;
+                       if (classpath) {
+                               // if (bundleContext != null) {
+                               Bundle currentBundle = bundleContext.getBundle();
+                               url = currentBundle.getResource(resUrl);
+                               // } else {
+                               // resUrl = "classpath:" + resUrl;
+                               // url = null;
+                               // }
+                       } else if (!resUrl.startsWith("classpath:")) {
+                               url = new URL(resUrl);
+                       }
+
+                       if (url != null) {
+                               in = url.openStream();
+                               // } else if (resourceLoader != null) {
+                               // Resource res = resourceLoader.getResource(resUrl);
+                               // in = res.getInputStream();
+                               // url = res.getURL();
+                       } else {
+                               throw new ArgeoException(
+                                               "No " + resUrl + " in the classpath," + " make sure the containing" + " package is visible.");
+                       }
+
+                       return IOUtils.toByteArray(in);
+               } catch (Exception e) {
+                       throw new ArgeoException("Cannot read CND from " + resUrl, e);
+               } finally {
+                       IOUtils.closeQuietly(in);
+               }
+       }
+
+       /*
+        * UTILITIES
+        */
+       /** Find which OSGi bundle provided the data model resource */
+       protected Bundle findDataModelBundle(String resUrl) {
+               BundleContext bundleContext = bc;
+               if (bundleContext == null)
+                       return null;
+
+               if (resUrl.startsWith("/"))
+                       resUrl = resUrl.substring(1);
+               String pkg = resUrl.substring(0, resUrl.lastIndexOf('/')).replace('/', '.');
+               ServiceReference<PackageAdmin> paSr = bundleContext.getServiceReference(PackageAdmin.class);
+               PackageAdmin packageAdmin = (PackageAdmin) bundleContext.getService(paSr);
+
+               // find exported package
+               ExportedPackage exportedPackage = null;
+               ExportedPackage[] exportedPackages = packageAdmin.getExportedPackages(pkg);
+               if (exportedPackages == null)
+                       throw new ArgeoException("No exported package found for " + pkg);
+               for (ExportedPackage ep : exportedPackages) {
+                       for (Bundle b : ep.getImportingBundles()) {
+                               if (b.getBundleId() == bundleContext.getBundle().getBundleId()) {
+                                       exportedPackage = ep;
+                                       break;
+                               }
+                       }
+               }
+
+               Bundle exportingBundle = null;
+               if (exportedPackage != null) {
+                       exportingBundle = exportedPackage.getExportingBundle();
+               } else {
+                       // assume this is in the same bundle
+                       exportingBundle = bundleContext.getBundle();
+                       // throw new ArgeoException("No OSGi exporting package found for "
+                       // + resUrl);
+               }
+               return exportingBundle;
+       }
+
+}
diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitNodeType.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitNodeType.java
new file mode 100644 (file)
index 0000000..5d78514
--- /dev/null
@@ -0,0 +1,6 @@
+package org.argeo.jackrabbit;
+
+/** The available Jackrabbit node types */
+public enum JackrabbitNodeType {
+       NOT_CONFIGURED, h2, postgresql, memory, localfs;
+}
diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/ManagedJackrabbitRepository.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/ManagedJackrabbitRepository.java
new file mode 100644 (file)
index 0000000..2ec8693
--- /dev/null
@@ -0,0 +1,263 @@
+package org.argeo.jackrabbit;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.jcr.Credentials;
+import javax.jcr.LoginException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.api.JackrabbitRepository;
+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.apache.jackrabbit.stats.RepositoryStatisticsImpl;
+import org.argeo.ArgeoException;
+import org.argeo.jcr.ArgeoJcrException;
+import org.argeo.jcr.JcrRepositoryWrapper;
+import org.argeo.jcr.RepoConf;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.xml.sax.InputSource;
+
+public class ManagedJackrabbitRepository extends JcrRepositoryWrapper implements ManagedService, JackrabbitRepository {
+       private final static Log log = LogFactory.getLog(ManagedJackrabbitRepository.class);
+
+       // Node
+       final static String REPO_TYPE = "repoType";
+       // final static String REPO_CONFIGURATION = "argeo.node.repo.configuration";
+       // final static String REPO_DEFAULT_WORKSPACE = "defaultWorkspace";
+       // final static String REPO_DBURL = "dburl";
+       // final static String REPO_DBUSER = "dbuser";
+       // final static String REPO_DBPASSWORD = "dbpassword";
+       // final static String REPO_MAX_POOL_SIZE = "maxPoolSize";
+       // final static String REPO_MAX_CACHE_MB = "maxCacheMB";
+       // final static String REPO_BUNDLE_CACHE_MB = "bundleCacheMB";
+       // final static String REPO_EXTRACTOR_POOL_SIZE = "extractorPoolSize";
+       // final static String REPO_SEARCH_CACHE_SIZE = "searchCacheSize";
+       // final static String REPO_MAX_VOLATILE_INDEX_SIZE =
+       // "maxVolatileIndexSize";
+
+       private Dictionary<String, ?> properties;
+
+       @Override
+       public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
+               this.properties = properties;
+               if (properties == null)
+                       return;
+
+               JackrabbitNodeType type = JackrabbitNodeType.valueOf(prop(RepoConf.type).toString());
+               try {
+                       repositoryContext = createNode(type);
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new ArgeoException("Cannot create Jackrabbit repository of type " + type, e);
+               }
+       }
+
+       private RepositoryContext repositoryContext;
+
+       public ManagedJackrabbitRepository() {
+               // setBundleContext(Activator.getBundleContext());
+               // JackrabbitNodeType type = JackrabbitNodeType.valueOf(prop(REPO_TYPE,
+               // JackrabbitNodeType.h2.name()));
+               // try {
+               // repositoryContext = createNode(type);
+               // cndFiles = Arrays.asList(DEFAULT_CNDS);
+               // prepareDataModel();
+               // } catch (Exception e) {
+               // throw new ArgeoException("Cannot create Jackrabbit repository of type
+               // " + type, e);
+               // }
+       }
+
+       public void destroy() {
+               ((RepositoryImpl) getRepository()).shutdown();
+       }
+
+       RepositoryStatisticsImpl getRepositoryStatistics() {
+               return repositoryContext.getRepositoryStatistics();
+       }
+
+       private RepositoryConfig getConfiguration(JackrabbitNodeType type, Hashtable<String, Object> props)
+                       throws RepositoryException {
+               ClassLoader cl = getClass().getClassLoader();
+               InputStream in = null;
+               try {
+                       final String base = "/org/argeo/jackrabbit";
+                       switch (type) {
+                       case h2:
+                               in = cl.getResourceAsStream(base + "/repository-h2.xml");
+                               break;
+                       case postgresql:
+                               in = cl.getResourceAsStream(base + "/repository-postgresql.xml");
+                               break;
+                       case memory:
+                               in = cl.getResourceAsStream(base + "/repository-memory.xml");
+                               break;
+                       case localfs:
+                               in = cl.getResourceAsStream(base + "/repository-localfs.xml");
+                               break;
+                       default:
+                               throw new ArgeoJcrException("Unsupported node type " + type);
+                       }
+
+                       if (in == null)
+                               throw new ArgeoJcrException("Repository configuration not found");
+                       InputSource config = new InputSource(in);
+                       Properties jackrabbitVars = new Properties();
+                       // convert values to Strings, otherwise they are skipped
+                       for (String key : props.keySet())
+                               jackrabbitVars.setProperty(key, props.get(key).toString());
+                       RepositoryConfig repositoryConfig = RepositoryConfig.create(config, jackrabbitVars);
+                       return repositoryConfig;
+               } finally {
+                       IOUtils.closeQuietly(in);
+               }
+       }
+
+       private Hashtable<String, Object> getConfigurationProperties(JackrabbitNodeType type) {
+               Hashtable<String, Object> props = new Hashtable<String, Object>();
+
+               // home
+               File osgiInstanceDir = getOsgiInstanceDir();
+               File homeDir = new File(osgiInstanceDir, "repos/node");
+               homeDir.mkdirs();
+               // home cannot be overridden
+               props.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, homeDir.getAbsolutePath());
+
+               // 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:" + homeDir.getPath() + "/h2/repository";
+                       setProp(props, RepoConf.dburl, dburl);
+                       setProp(props, RepoConf.dbuser, "sa");
+                       setProp(props, RepoConf.dbpassword, "");
+                       break;
+               case postgresql:
+                       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 ArgeoJcrException("Unsupported node type " + type);
+               }
+               return props;
+       }
+
+       private void setProp(Dictionary<String, Object> props, RepoConf key, String def) {
+               Object value = prop(key);
+               if (value == null)
+                       value = def;
+               props.put(key.name(), value);
+       }
+
+       private void setProp(Dictionary<String, Object> props, RepoConf key) {
+               setProp(props, key, null);
+       }
+
+       private Object prop(RepoConf key) {
+               if (properties == null)
+                       throw new ArgeoJcrException("Properties are not set");
+               Object value = properties.get(key.name());
+               if (value == null)
+                       return key.getDefault();
+               else
+                       return value;
+       }
+
+       private RepositoryContext createNode(JackrabbitNodeType type) throws RepositoryException {
+               Hashtable<String, Object> props = getConfigurationProperties(type);
+               RepositoryConfig repositoryConfig = getConfiguration(type, props);
+               RepositoryContext repositoryContext = createJackrabbitRepository(repositoryConfig);
+               RepositoryImpl repository = repositoryContext.getRepository();
+
+               // cache
+               Object maxCacheMbStr = prop(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);
+               }
+
+               // wrap the repository
+               setRepository(repository);
+               return repositoryContext;
+       }
+
+       private RepositoryContext createJackrabbitRepository(RepositoryConfig repositoryConfig) throws RepositoryException {
+               long begin = System.currentTimeMillis();
+               //
+               // Actual repository creation
+               //
+               RepositoryContext repositoryContext = RepositoryContext.create(repositoryConfig);
+
+               double duration = ((double) (System.currentTimeMillis() - begin)) / 1000;
+               if (log.isTraceEnabled())
+                       log.trace("Created Jackrabbit repository in " + duration + " s, home: " + repositoryConfig.getHomeDir());
+
+               return repositoryContext;
+       }
+
+       /*
+        * DATA MODEL
+        */
+
+       public synchronized void waitForInit() {
+               while (repositoryContext == null)
+                       try {
+                               wait(100);
+                       } catch (InterruptedException e) {
+                               return;
+                       }
+       }
+
+       private final static String OSGI_INSTANCE_AREA = "osgi.instance.area";
+
+       private File getOsgiInstanceDir() {
+               String instanceArea = System.getProperty(OSGI_INSTANCE_AREA);
+               return new File(instanceArea.substring("file:".length())).getAbsoluteFile();
+       }
+
+       @Override
+       public Session login(Credentials credentials, String workspaceName, Map<String, Object> attributes)
+                       throws LoginException, NoSuchWorkspaceException, RepositoryException {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       public void shutdown() {
+               destroy();
+
+       }
+
+}
diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-fs.xml b/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-fs.xml
deleted file mode 100644 (file)
index 609fc8b..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN"
-                            "http://jackrabbit.apache.org/dtd/repository-2.0.dtd">
-<Repository>
-       <!-- File system and datastore -->
-       <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
-               <param name="path" value="${rep.home}/fs" />
-       </FileSystem>
-       <DataStore class="org.apache.jackrabbit.core.data.FileDataStore">
-               <param name="path" value="${rep.home}/datastore" />
-       </DataStore>
-
-       <!-- Workspace templates -->
-       <Workspaces rootPath="${rep.home}/workspaces"
-               defaultWorkspace="${argeo.node.repo.defaultWorkspace}" />
-       <Workspace name="${wsp.name}">
-               <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
-                       <param name="path" value="${wsp.home}" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.bundle.BundleFsPersistenceManager" />
-               <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-                       <param name="path" value="${wsp.home}/index" />
-               </SearchIndex>
-       </Workspace>
-
-       <!-- Versioning -->
-       <Versioning rootPath="${rep.home}/version">
-               <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
-                       <param name="path" value="${rep.home}/version" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.bundle.BundleFsPersistenceManager" />
-       </Versioning>
-
-       <!-- Indexing -->
-       <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-               <param name="path" value="${rep.home}/index" />
-               <param name="extractorPoolSize" value="2" />
-               <param name="supportHighlighting" value="true" />
-       </SearchIndex>
-
-       <!-- Security -->
-       <Security appName="Jackrabbit">
-               <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
-                       workspaceName="security">
-               </SecurityManager>
-               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager">
-               </AccessManager>
-               <LoginModule class="org.argeo.security.jackrabbit.ArgeoLoginModule">
-               </LoginModule>
-       </Security>
-</Repository>
\ No newline at end of file
index b6a92528a3fd2d09c32dfc78e3da6b6ecfa91887..05267621f7d951046b16a70fd7399821bd986ff5 100644 (file)
@@ -1,16 +1,15 @@
-<?xml version="1.0"?>
-<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN"
-                            "http://jackrabbit.apache.org/dtd/repository-2.0.dtd">
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Repository PUBLIC "Jackrabbit 2.6" "http://jackrabbit.apache.org/dtd/repository-2.6.dtd">
 <Repository>
        <!-- Shared datasource -->
        <DataSources>
                <DataSource name="dataSource">
                        <param name="driver" value="org.h2.Driver" />
-                       <param name="url" value="jdbc:h2:${rep.home}/h2/repository" />
-                       <param name="user" value="sa" />
-                       <param name="password" value="" />
+                       <param name="url" value="${dburl}" />
+                       <param name="user" value="${dbuser}" />
+                       <param name="password" value="${dbpassword}" />
                        <param name="databaseType" value="h2" />
-                       <param name="maxPoolSize" value="10" />
+                       <param name="maxPoolSize" value="${maxPoolSize}" />
                </DataSource>
        </DataSources>
 
@@ -26,7 +25,7 @@
 
        <!-- Workspace templates -->
        <Workspaces rootPath="${rep.home}/workspaces"
-               defaultWorkspace="main" />
+               defaultWorkspace="${defaultWorkspace}" />
        <Workspace name="${wsp.name}">
                <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
                        <param name="dataSourceName" value="dataSource" />
                        class="org.apache.jackrabbit.core.persistence.pool.H2PersistenceManager">
                        <param name="dataSourceName" value="dataSource" />
                        <param name="schemaObjectPrefix" value="${wsp.name}_pm_" />
+                       <param name="bundleCacheSize" value="${bundleCacheMB}" />
                </PersistenceManager>
                <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
                        <param name="path" value="${wsp.home}/index" />
+                       <param name="extractorPoolSize" value="${extractorPoolSize}" />
+                       <param name="cacheSize" value="${searchCacheSize}" />
+                       <param name="maxVolatileIndexSize" value="${maxVolatileIndexSize}" />
                </SearchIndex>
+               <WorkspaceSecurity>
+                       <AccessControlProvider
+                               class="org.argeo.security.jackrabbit.ArgeoAccessControlProvider" />
+               </WorkspaceSecurity>
        </Workspace>
 
        <!-- Versioning -->
                        class="org.apache.jackrabbit.core.persistence.pool.H2PersistenceManager">
                        <param name="dataSourceName" value="dataSource" />
                        <param name="schemaObjectPrefix" value="pm_ver_" />
+                       <param name="bundleCacheSize" value="${bundleCacheMB}" />
                </PersistenceManager>
        </Versioning>
 
        <!-- Indexing -->
        <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
                <param name="path" value="${rep.home}/index" />
-               <param name="extractorPoolSize" value="2" />
-               <param name="supportHighlighting" value="true" />
+               <param name="extractorPoolSize" value="${extractorPoolSize}" />
+               <param name="cacheSize" value="${searchCacheSize}" />
+               <param name="maxVolatileIndexSize" value="${maxVolatileIndexSize}" />
        </SearchIndex>
 
        <!-- Security -->
        <Security appName="Jackrabbit">
                <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
-                       workspaceName="security">
-               </SecurityManager>
-               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager">
-               </AccessManager>
-               <LoginModule class="org.argeo.security.jackrabbit.ArgeoLoginModule">
-               </LoginModule>
+                       workspaceName="security" />
+               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager" />
        </Security>
 </Repository>
\ No newline at end of file
diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-localfs.xml b/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-localfs.xml
new file mode 100644 (file)
index 0000000..3d24708
--- /dev/null
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE Repository PUBLIC "Jackrabbit 2.6" "http://jackrabbit.apache.org/dtd/repository-2.6.dtd">
+<Repository>
+       <!-- File system and datastore -->
+       <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+               <param name="path" value="${rep.home}/repository" />
+       </FileSystem>
+       <DataStore class="org.apache.jackrabbit.core.data.FileDataStore">
+               <param name="path" value="${rep.home}/datastore" />
+       </DataStore>
+
+       <!-- Workspace templates -->
+       <Workspaces rootPath="${rep.home}/workspaces"
+               defaultWorkspace="${defaultWorkspace}" />
+       <Workspace name="${wsp.name}">
+               <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+                       <param name="path" value="${wsp.home}" />
+               </FileSystem>
+               <PersistenceManager
+                       class="org.apache.jackrabbit.core.persistence.bundle.BundleFsPersistenceManager">
+                       <param name="bundleCacheSize" value="${bundleCacheMB}" />
+               </PersistenceManager>
+               <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+                       <param name="path" value="${wsp.home}/index" />
+                       <param name="extractorPoolSize" value="${extractorPoolSize}" />
+                       <param name="cacheSize" value="${searchCacheSize}" />
+                       <param name="maxVolatileIndexSize" value="${maxVolatileIndexSize}" />
+               </SearchIndex>
+               <WorkspaceSecurity>
+                       <AccessControlProvider
+                               class="org.argeo.security.jackrabbit.ArgeoAccessControlProvider" />
+               </WorkspaceSecurity>
+       </Workspace>
+
+       <!-- Versioning -->
+       <Versioning rootPath="${rep.home}/version">
+               <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+                       <param name="path" value="${rep.home}/version" />
+               </FileSystem>
+               <PersistenceManager
+                       class="org.apache.jackrabbit.core.persistence.bundle.BundleFsPersistenceManager">
+                       <param name="bundleCacheSize" value="${bundleCacheMB}" />
+               </PersistenceManager>
+       </Versioning>
+
+       <!-- Indexing -->
+       <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+               <param name="path" value="${rep.home}/index" />
+               <param name="extractorPoolSize" value="${extractorPoolSize}" />
+               <param name="cacheSize" value="${searchCacheSize}" />
+               <param name="maxVolatileIndexSize" value="${maxVolatileIndexSize}" />
+       </SearchIndex>
+
+       <!-- Security -->
+       <Security appName="Jackrabbit">
+               <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
+                       workspaceName="security" />
+               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager" />
+       </Security>
+</Repository>
\ No newline at end of file
index e552c33a776c94a8983f86d8c43d2c4d3aea1d3d..ecee5bdad02607fe429c46b526b2511935074709 100644 (file)
@@ -1,40 +1,26 @@
 <?xml version="1.0"?>
-<!--
-
-    Copyright (C) 2007-2012 Argeo GmbH
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-            http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
-
--->
-<!DOCTYPE Repository PUBLIC "-//The Apache Software Foundation//DTD Jackrabbit 1.6//EN"
-                            "http://jackrabbit.apache.org/dtd/repository-2.0.dtd">
+<!DOCTYPE Repository PUBLIC "Jackrabbit 2.6" "http://jackrabbit.apache.org/dtd/repository-2.6.dtd">
 <Repository>
        <!-- File system and datastore -->
        <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem" />
 
        <!-- Workspace templates -->
        <Workspaces rootPath="${rep.home}/workspaces"
-               defaultWorkspace="main" configRootPath="/workspaces" />
+               defaultWorkspace="${defaultWorkspace}" configRootPath="/workspaces" />
        <Workspace name="${wsp.name}">
                <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem" />
                <PersistenceManager
                        class="org.apache.jackrabbit.core.persistence.bundle.BundleFsPersistenceManager">
                        <param name="blobFSBlockSize" value="1" />
+                       <param name="bundleCacheSize" value="${bundleCacheMB}" />
                </PersistenceManager>
                <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-                       <param name="path" value="${rep.home}/repository/index" />
+                       <param name="path" value="${wsp.home}/index" />
                        <param name="directoryManagerClass"
                                value="org.apache.jackrabbit.core.query.lucene.directory.RAMDirectoryManager" />
+                       <param name="extractorPoolSize" value="${extractorPoolSize}" />
+                       <param name="cacheSize" value="${searchCacheSize}" />
+                       <param name="maxVolatileIndexSize" value="${maxVolatileIndexSize}" />
                        <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem" />
                </SearchIndex>
        </Workspace>
                <PersistenceManager
                        class="org.apache.jackrabbit.core.persistence.bundle.BundleFsPersistenceManager">
                        <param name="blobFSBlockSize" value="1" />
+                       <param name="bundleCacheSize" value="${bundleCacheMB}" />
                </PersistenceManager>
        </Versioning>
 
        <!-- Indexing -->
        <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-               <param name="path" value="${rep.home}/repository/index" />
+               <param name="path" value="${rep.home}/index" />
                <param name="directoryManagerClass"
                        value="org.apache.jackrabbit.core.query.lucene.directory.RAMDirectoryManager" />
+               <param name="extractorPoolSize" value="${extractorPoolSize}" />
+               <param name="cacheSize" value="${searchCacheSize}" />
+               <param name="maxVolatileIndexSize" value="${maxVolatileIndexSize}" />
                <FileSystem class="org.apache.jackrabbit.core.fs.mem.MemoryFileSystem" />
        </SearchIndex>
 
        <!-- Security -->
        <Security appName="Jackrabbit">
                <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
-                       workspaceName="security">
-               </SecurityManager>
-               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager">
-               </AccessManager>
-               <LoginModule class="org.argeo.security.jackrabbit.ArgeoLoginModule">
-               </LoginModule>
+                       workspaceName="security" />
+               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager" />
        </Security>
 </Repository>
\ No newline at end of file
diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-postgresql-ds.xml b/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-postgresql-ds.xml
new file mode 100644 (file)
index 0000000..07a0d04
--- /dev/null
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<!DOCTYPE Repository PUBLIC "Jackrabbit 2.6" "http://jackrabbit.apache.org/dtd/repository-2.6.dtd">
+<Repository>
+       <!-- Shared datasource -->
+       <DataSources>
+               <DataSource name="dataSource">
+                       <param name="driver" value="org.postgresql.Driver" />
+                       <param name="url" value="${dburl}" />
+                       <param name="user" value="${dbuser}" />
+                       <param name="password" value="${dbpassword}" />
+                       <param name="databaseType" value="postgresql" />
+                       <param name="maxPoolSize" value="${maxPoolSize}" />
+               </DataSource>
+       </DataSources>
+
+       <!-- File system and datastore -->
+       <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
+               <param name="dataSourceName" value="dataSource" />
+               <param name="schema" value="postgresql" />
+               <param name="schemaObjectPrefix" value="fs_" />
+       </FileSystem>
+       <DataStore class="org.apache.jackrabbit.core.data.FileDataStore">
+               <param name="path" value="${rep.home}/datastore" />
+       </DataStore>
+
+       <!-- Workspace templates -->
+       <Workspaces rootPath="${rep.home}/workspaces"
+               defaultWorkspace="${defaultWorkspace}" />
+       <Workspace name="${wsp.name}">
+               <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
+                       <param name="dataSourceName" value="dataSource" />
+                       <param name="schema" value="postgresql" />
+                       <param name="schemaObjectPrefix" value="${wsp.name}_fs_" />
+               </FileSystem>
+               <PersistenceManager
+                       class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
+                       <param name="dataSourceName" value="dataSource" />
+                       <param name="schemaObjectPrefix" value="${wsp.name}_pm_" />
+                       <param name="bundleCacheSize" value="${bundleCacheMB}" />
+               </PersistenceManager>
+               <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+                       <param name="path" value="${wsp.home}/index" />
+                       <param name="extractorPoolSize" value="${extractorPoolSize}" />
+                       <param name="cacheSize" value="${searchCacheSize}" />
+                       <param name="maxVolatileIndexSize" value="${maxVolatileIndexSize}" />
+               </SearchIndex>
+               <WorkspaceSecurity>
+                       <AccessControlProvider
+                               class="org.argeo.security.jackrabbit.ArgeoAccessControlProvider" />
+               </WorkspaceSecurity>
+       </Workspace>
+
+       <!-- Versioning -->
+       <Versioning rootPath="${rep.home}/version">
+               <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
+                       <param name="dataSourceName" value="dataSource" />
+                       <param name="schema" value="postgresql" />
+                       <param name="schemaObjectPrefix" value="fs_ver_" />
+               </FileSystem>
+               <PersistenceManager
+                       class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
+                       <param name="dataSourceName" value="dataSource" />
+                       <param name="schemaObjectPrefix" value="pm_ver_" />
+                       <param name="bundleCacheSize" value="${bundleCacheMB}" />
+               </PersistenceManager>
+       </Versioning>
+
+       <!-- Indexing -->
+       <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+               <param name="path" value="${rep.home}/index" />
+               <param name="extractorPoolSize" value="${extractorPoolSize}" />
+               <param name="cacheSize" value="${searchCacheSize}" />
+               <param name="maxVolatileIndexSize" value="${maxVolatileIndexSize}" />
+       </SearchIndex>
+
+       <!-- Security -->
+       <Security appName="Jackrabbit">
+               <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
+                       workspaceName="security" />
+               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager" />
+       </Security>
+</Repository>
\ No newline at end of file
diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-postgresql.xml b/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-postgresql.xml
new file mode 100644 (file)
index 0000000..9677828
--- /dev/null
@@ -0,0 +1,79 @@
+<?xml version="1.0"?>
+<!DOCTYPE Repository PUBLIC "Jackrabbit 2.6" "http://jackrabbit.apache.org/dtd/repository-2.6.dtd">
+<Repository>
+       <!-- Shared datasource -->
+       <DataSources>
+               <DataSource name="dataSource">
+                       <param name="driver" value="org.postgresql.Driver" />
+                       <param name="url" value="${dburl}" />
+                       <param name="user" value="${dbuser}" />
+                       <param name="password" value="${dbpassword}" />
+                       <param name="databaseType" value="postgresql" />
+                       <param name="maxPoolSize" value="${maxPoolSize}" />
+               </DataSource>
+       </DataSources>
+
+       <!-- File system and datastore -->
+       <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
+               <param name="dataSourceName" value="dataSource" />
+               <param name="schema" value="postgresql" />
+               <param name="schemaObjectPrefix" value="fs_" />
+       </FileSystem>
+
+       <!-- Workspace templates -->
+       <Workspaces rootPath="${rep.home}/workspaces"
+               defaultWorkspace="${defaultWorkspace}" />
+       <Workspace name="${wsp.name}">
+               <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
+                       <param name="dataSourceName" value="dataSource" />
+                       <param name="schema" value="postgresql" />
+                       <param name="schemaObjectPrefix" value="${wsp.name}_fs_" />
+               </FileSystem>
+               <PersistenceManager
+                       class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
+                       <param name="dataSourceName" value="dataSource" />
+                       <param name="schemaObjectPrefix" value="${wsp.name}_pm_" />
+                       <param name="bundleCacheSize" value="${bundleCacheMB}" />
+               </PersistenceManager>
+               <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+                       <param name="path" value="${wsp.home}/index" />
+                       <param name="extractorPoolSize" value="${extractorPoolSize}" />
+                       <param name="cacheSize" value="${searchCacheSize}" />
+                       <param name="maxVolatileIndexSize" value="${maxVolatileIndexSize}" />
+               </SearchIndex>
+               <WorkspaceSecurity>
+                       <AccessControlProvider
+                               class="org.argeo.security.jackrabbit.ArgeoAccessControlProvider" />
+               </WorkspaceSecurity>
+       </Workspace>
+
+       <!-- Versioning -->
+       <Versioning rootPath="${rep.home}/version">
+               <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
+                       <param name="dataSourceName" value="dataSource" />
+                       <param name="schema" value="postgresql" />
+                       <param name="schemaObjectPrefix" value="fs_ver_" />
+               </FileSystem>
+               <PersistenceManager
+                       class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
+                       <param name="dataSourceName" value="dataSource" />
+                       <param name="schemaObjectPrefix" value="pm_ver_" />
+                       <param name="bundleCacheSize" value="${bundleCacheMB}" />
+               </PersistenceManager>
+       </Versioning>
+
+       <!-- Indexing -->
+       <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+               <param name="path" value="${rep.home}/index" />
+               <param name="extractorPoolSize" value="${extractorPoolSize}" />
+               <param name="cacheSize" value="${searchCacheSize}" />
+               <param name="maxVolatileIndexSize" value="${maxVolatileIndexSize}" />
+       </SearchIndex>
+
+       <!-- Security -->
+       <Security appName="Jackrabbit">
+               <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
+                       workspaceName="security" />
+               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager" />
+       </Security>
+</Repository>
\ No newline at end of file
index 8b64b332e20606b9b090fa1c1f35365d6f795cbb..53e494cff0f158b2bacdcffc0245e6ab6b276be5 100644 (file)
@@ -20,10 +20,8 @@ import javax.jcr.Repository;
 /** Argeo model specific constants */
 public interface ArgeoJcrConstants {
        public final static String ARGEO_BASE_PATH = "/argeo:system";
-       public final static String DATA_MODELS_BASE_PATH = ARGEO_BASE_PATH
-                       + "/argeo:dataModels";
-       public final static String PEOPLE_BASE_PATH = ARGEO_BASE_PATH
-                       + "/argeo:people";
+       public final static String DATA_MODELS_BASE_PATH = ARGEO_BASE_PATH + "/argeo:dataModels";
+       public final static String PEOPLE_BASE_PATH = ARGEO_BASE_PATH + "/argeo:people";
 
        // parameters (typically for call to a RepositoryFactory)
        /** Key for a JCR repository alias */
@@ -37,5 +35,7 @@ public interface ArgeoJcrConstants {
         * JCR repository.
         */
        public final static String ALIAS_NODE = "node";
+       public final static String BASE_REPO_PID = "argeo.repo.";
+       public final static String REPO_PID_NODE = BASE_REPO_PID + ALIAS_NODE;
 
 }
diff --git a/org.argeo.server.jcr/src/org/argeo/jcr/ArgeoJcrException.java b/org.argeo.server.jcr/src/org/argeo/jcr/ArgeoJcrException.java
new file mode 100644 (file)
index 0000000..8e19593
--- /dev/null
@@ -0,0 +1,15 @@
+package org.argeo.jcr;
+
+/** Argeo JCR specific exceptions. */
+public class ArgeoJcrException extends RuntimeException {
+       private static final long serialVersionUID = -1941940005390084331L;
+
+       public ArgeoJcrException(String message, Throwable cause) {
+               super(message, cause);
+       }
+
+       public ArgeoJcrException(String message) {
+               super(message);
+       }
+
+}
diff --git a/org.argeo.server.jcr/src/org/argeo/jcr/RepoConf.java b/org.argeo.server.jcr/src/org/argeo/jcr/RepoConf.java
new file mode 100644 (file)
index 0000000..28275d6
--- /dev/null
@@ -0,0 +1,42 @@
+package org.argeo.jcr;
+
+/** JCR repository configuration */
+public enum RepoConf {
+       /** Repository type */
+       type("localfs"),
+       /** Default workspace */
+       defaultWorkspace("main"),
+       /** Database URL */
+       dburl(null),
+       /** Database user */
+       dbuser(null),
+       /** Database password */
+       dbpassword(null),
+
+       //
+       // JACKRABBIT SPECIFIC
+       //
+       /** Maximum database pool size */
+       maxPoolSize(10),
+       /** Maximum cache size in MB */
+       maxCacheMB(null),
+       /** Bundle cache size in MB */
+       bundleCacheMB(8),
+       /** Extractor pool size */
+       extractorPoolSize(0),
+       /** Search cache size */
+       searchCacheSize(1000),
+       /** Max volatile index size */
+       maxVolatileIndexSize(1048576);
+
+       /** The default value. */
+       private Object def;
+
+       RepoConf(Object def) {
+               this.def = def;
+       }
+
+       public Object getDefault() {
+               return def;
+       }
+}