From: Mathieu Baudier Date: Tue, 9 Aug 2016 16:39:43 +0000 (+0000) Subject: Working Argeo 2 deployment (with UI) X-Git-Tag: argeo-commons-2.1.45~37 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=b4c772a263e0f19f6c283dbbb87d04794072b284;p=lgpl%2Fargeo-commons.git Working Argeo 2 deployment (with UI) git-svn-id: https://svn.argeo.org/commons/trunk@9074 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/demo/argeo_node_rap.properties b/demo/argeo_node_rap.properties index e0805f8a1..3e7ec6651 100644 --- a/demo/argeo_node_rap.properties +++ b/demo/argeo_node_rap.properties @@ -1,10 +1,10 @@ argeo.osgi.start.2.node=\ org.eclipse.equinox.http.servlet,\ org.eclipse.equinox.http.jetty,\ +org.eclipse.equinox.metatype,\ org.eclipse.equinox.cm,\ org.eclipse.rap.rwt.osgi -#org.eclipse.equinox.metatype,\ argeo.osgi.start.3.node=\ org.argeo.cms diff --git a/org.argeo.cms.api/src/org/argeo/node/EnumAD.java b/org.argeo.cms.api/src/org/argeo/node/EnumAD.java new file mode 100644 index 000000000..1ee6d39f0 --- /dev/null +++ b/org.argeo.cms.api/src/org/argeo/node/EnumAD.java @@ -0,0 +1,59 @@ +package org.argeo.node; + +import org.osgi.service.metatype.AttributeDefinition; + +interface EnumAD extends AttributeDefinition { + String name(); + + default Object getDefault() { + return null; + } + + @Override + default String getName() { + return name(); + } + + @Override + default String getID() { + return getClass().getName() + "." + name(); + } + + @Override + default String getDescription() { + return null; + } + + @Override + default int getCardinality() { + return 0; + } + + @Override + default int getType() { + return STRING; + } + + @Override + default String[] getOptionValues() { + return null; + } + + @Override + default String[] getOptionLabels() { + return null; + } + + @Override + default String validate(String value) { + return null; + } + + @Override + default String[] getDefaultValue() { + Object value = getDefault(); + if (value == null) + return null; + return new String[] { value.toString() }; + } +} diff --git a/org.argeo.cms.api/src/org/argeo/node/EnumOCD.java b/org.argeo.cms.api/src/org/argeo/node/EnumOCD.java new file mode 100644 index 000000000..daa2f540d --- /dev/null +++ b/org.argeo.cms.api/src/org/argeo/node/EnumOCD.java @@ -0,0 +1,50 @@ +package org.argeo.node; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + +import org.osgi.service.metatype.AttributeDefinition; +import org.osgi.service.metatype.ObjectClassDefinition; + +class EnumOCD> implements ObjectClassDefinition { + private final Class enumClass; + private String locale; + + public EnumOCD(Class clazz, String locale) { + this.enumClass = clazz; + this.locale = locale; + } + + @Override + public String getName() { + return null; + } + + @Override + public String getID() { + return enumClass.getName(); + } + + @Override + public String getDescription() { + return null; + } + + @Override + public AttributeDefinition[] getAttributeDefinitions(int filter) { + EnumSet set = EnumSet.allOf(enumClass); + List attrs = new ArrayList<>(); + for (T key : set) + attrs.add((AttributeDefinition) key); + return attrs.toArray(new AttributeDefinition[attrs.size()]); + } + + @Override + public InputStream getIcon(int size) throws IOException { + return null; + } + +} diff --git a/org.argeo.cms.api/src/org/argeo/node/NodeConstants.java b/org.argeo.cms.api/src/org/argeo/node/NodeConstants.java index 7b7d6dc35..138979205 100644 --- a/org.argeo.cms.api/src/org/argeo/node/NodeConstants.java +++ b/org.argeo.cms.api/src/org/argeo/node/NodeConstants.java @@ -10,7 +10,7 @@ public interface NodeConstants { String NODE_REPO_PID = "org.argeo.node.repo"; String NODE_USER_ADMIN_PID = "org.argeo.node.userAdmin"; - + /* * FACTORY PIDs */ @@ -30,4 +30,9 @@ public interface NodeConstants { /** Properties configuring the node repository */ String NODE_REPO_PROP_PREFIX = "argeo.node.repo."; + /* + * STANDARD ATTRIBUTES + */ + String CN = "cn"; + String LABELED_URI = "labeledUri"; } diff --git a/org.argeo.cms.api/src/org/argeo/node/NodeDeployment.java b/org.argeo.cms.api/src/org/argeo/node/NodeDeployment.java index 5889e5054..1b04d6809 100644 --- a/org.argeo.cms.api/src/org/argeo/node/NodeDeployment.java +++ b/org.argeo.cms.api/src/org/argeo/node/NodeDeployment.java @@ -1,5 +1,5 @@ package org.argeo.node; public interface NodeDeployment { - + long getAvailableSince(); } diff --git a/org.argeo.cms.api/src/org/argeo/node/NodeOID.java b/org.argeo.cms.api/src/org/argeo/node/NodeOID.java new file mode 100644 index 000000000..9d8ff3d3a --- /dev/null +++ b/org.argeo.cms.api/src/org/argeo/node/NodeOID.java @@ -0,0 +1,18 @@ +package org.argeo.node; + +interface NodeOID { + String BASE = "1.3.6.1.4.1" + ".48308" + ".1"; + + // ATTRIBUTE TYPES + String ATTRIBUTE_TYPES = BASE + ".4"; + String URI = ATTRIBUTE_TYPES + ".1"; + String HTTP_PORT = ATTRIBUTE_TYPES + ".2"; + String HTTPS_PORT = ATTRIBUTE_TYPES + ".3"; + + // OBJECT CLASSES + String OBJECT_CLASSES = BASE + ".6"; + String JCR_REPOSITORY = OBJECT_CLASSES + ".1"; + + // EXTERNAL + String LABELED_URI = "1.3.6.1.4.1.250.1.57"; +} diff --git a/org.argeo.cms.api/src/org/argeo/node/NodeState.java b/org.argeo.cms.api/src/org/argeo/node/NodeState.java index f7d7042a8..572d7eea4 100644 --- a/org.argeo.cms.api/src/org/argeo/node/NodeState.java +++ b/org.argeo.cms.api/src/org/argeo/node/NodeState.java @@ -4,7 +4,9 @@ import java.util.List; import java.util.Locale; public interface NodeState { - public Locale getDefaultLocale(); + Locale getDefaultLocale(); - public List getLocales(); + List getLocales(); + + String getHostname(); } diff --git a/org.argeo.cms.api/src/org/argeo/node/RepoConf.java b/org.argeo.cms.api/src/org/argeo/node/RepoConf.java index 39f72c035..90d33322f 100644 --- a/org.argeo.cms.api/src/org/argeo/node/RepoConf.java +++ b/org.argeo.cms.api/src/org/argeo/node/RepoConf.java @@ -1,7 +1,7 @@ package org.argeo.node; /** JCR repository configuration */ -public enum RepoConf { +public enum RepoConf implements EnumAD { /** Repository type */ type("localfs"), /** Default workspace */ @@ -14,8 +14,9 @@ public enum RepoConf { dbpassword(null), /** The identifier (can be an URL locating the repo) */ - uri(null), + labeledUri(null), + httpPort(8080), // // JACKRABBIT SPECIFIC // @@ -34,6 +35,12 @@ public enum RepoConf { /** The default value. */ private Object def; + private String oid; + + RepoConf(String oid, Object def) { + this.oid = oid; + this.def = def; + } RepoConf(Object def) { this.def = def; @@ -42,4 +49,18 @@ public enum RepoConf { public Object getDefault() { return def; } + + @Override + public String getID() { + if (oid != null) + return oid; + return EnumAD.super.getID(); + } + + public static class OCD extends EnumOCD { + public OCD(String locale) { + super(RepoConf.class, locale); + } + } + } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java index 1997b73ce..3546647dd 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java @@ -4,6 +4,8 @@ import java.io.IOException; import java.net.URL; import java.util.Dictionary; import java.util.Hashtable; +import java.util.List; +import java.util.Locale; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -17,7 +19,6 @@ import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; -import org.osgi.framework.ServiceRegistration; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.cm.ManagedService; @@ -38,7 +39,7 @@ public class Activator implements BundleActivator { // System.setProperty(SYSTEM_KEY_PROPERTY, systemKey); // } -// private static Kernel kernel; + // private static Kernel kernel; private static Activator instance; private BundleContext bc; @@ -83,18 +84,20 @@ public class Activator implements BundleActivator { private void initNodeState() throws IOException { nodeState = new CmsState(); - bc.registerService(LangUtils.names(NodeState.class, ManagedService.class), nodeState, - LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_STATE_PID)); + Object cn; Configuration nodeConf = configurationAdmin.getConfiguration(NodeConstants.NODE_STATE_PID); Dictionary props = nodeConf.getProperties(); if (props == null) { if (log.isDebugEnabled()) log.debug("Clean node state"); Dictionary envProps = getStatePropertiesFromEnvironment(); + // Use the UUID of the first framework run as state UUID + cn = KernelUtils.getFrameworkProp(Constants.FRAMEWORK_UUID); + envProps.put(NodeConstants.CN, cn); nodeConf.update(envProps); } else { - // Check id state is in line with environment + // Check if state is in line with environment Dictionary envProps = getStatePropertiesFromEnvironment(); for (String key : LangUtils.keys(envProps)) { Object envValue = envProps.get(key); @@ -106,8 +109,15 @@ public class Activator implements BundleActivator { throw new CmsException("State value for " + key + "=" + storedValue + " is different from env value =" + envValue + ", please clean the OSGi configuration."); } + cn = props.get(NodeConstants.CN); + if (cn == null) + throw new CmsException("No state UUID available"); } + Dictionary regProps = LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_STATE_PID); + regProps.put(NodeConstants.CN, cn); + bc.registerService(LangUtils.names(NodeState.class, ManagedService.class), nodeState, regProps); + } @Override @@ -120,10 +130,10 @@ public class Activator implements BundleActivator { this.logReaderService = null; this.configurationAdmin = null; -// if (kernel != null) { -// kernel.destroy(); -// kernel = null; -// } + // if (kernel != null) { + // kernel.destroy(); + // kernel = null; + // } } @@ -158,4 +168,14 @@ public class Activator implements BundleActivator { public static NodeState getNodeState() { return instance.nodeState; } + + public String[] getLocales() { + // TODO optimize? + List locales = getNodeState().getLocales(); + String[] res = new String[locales.size()]; + for (int i = 0; i < locales.size(); i++) + res[i] = locales.get(i).toString(); + return res; + } + } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java index 6fbe7a95c..b36e0f4c5 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java @@ -38,19 +38,32 @@ public class CmsDeployment implements NodeDeployment, ManagedService { private Repository deployedNodeRepository; private HomeRepository homeRepository; - + + private Long availableSince; + @Override public void updated(Dictionary properties) throws ConfigurationException { if (properties == null) return; - prepareDataModel(KernelUtils.openAdminSession(deployedNodeRepository)); - Hashtable regProps = new Hashtable(); - regProps.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, ArgeoJcrConstants.ALIAS_HOME); - homeRepository = new HomeRepository(deployedNodeRepository); - // register - bc.registerService(Repository.class, homeRepository, regProps); -} + if (deployedNodeRepository != null) { + if (availableSince != null) { + throw new CmsException("Deployment is already available"); + } + + availableSince = System.currentTimeMillis(); + + prepareDataModel(KernelUtils.openAdminSession(deployedNodeRepository)); + Hashtable regProps = new Hashtable(); + regProps.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, ArgeoJcrConstants.ALIAS_HOME); + homeRepository = new HomeRepository(deployedNodeRepository); + // register + bc.registerService(Repository.class, homeRepository, regProps); + + } else { + throw new CmsException("No node repository available"); + } + } /** Session is logged out. */ private void prepareDataModel(Session adminSession) { @@ -113,5 +126,9 @@ public class CmsDeployment implements NodeDeployment, ManagedService { this.deployedNodeRepository = deployedNodeRepository; } - + @Override + public long getAvailableSince() { + return availableSince; + } + } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java index ca6341aed..f975d6cf8 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java @@ -9,7 +9,12 @@ import static org.osgi.framework.Constants.FRAMEWORK_UUID; import java.io.File; import java.io.IOException; +import java.net.InetAddress; import java.net.URI; +import java.net.UnknownHostException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Dictionary; import java.util.Hashtable; import java.util.List; @@ -22,9 +27,9 @@ import javax.transaction.UserTransaction; 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.argeo.cms.CmsException; -import org.argeo.jackrabbit.OsgiJackrabbitRepositoryFactory; +import org.argeo.cms.maintenance.MaintenanceUi; import org.argeo.jcr.ArgeoJcrConstants; import org.argeo.node.NodeConstants; import org.argeo.node.NodeDeployment; @@ -33,6 +38,7 @@ import org.argeo.node.RepoConf; import org.argeo.util.LangUtils; import org.eclipse.equinox.http.jetty.JettyConfigurator; import org.eclipse.equinox.http.jetty.JettyConstants; +import org.eclipse.rap.rwt.application.ApplicationConfiguration; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; @@ -44,6 +50,7 @@ import org.osgi.service.cm.ConfigurationException; import org.osgi.service.cm.ManagedService; import org.osgi.service.cm.ManagedServiceFactory; import org.osgi.service.http.HttpService; +import org.osgi.service.metatype.MetaTypeProvider; import org.osgi.service.useradmin.UserAdmin; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; @@ -56,6 +63,9 @@ public class CmsState implements NodeState, ManagedService { private final Log log = LogFactory.getLog(CmsState.class); private final BundleContext bc = FrameworkUtil.getBundle(CmsState.class).getBundleContext(); + // avoid dependency to RWT OSGi + private final static String PROPERTY_CONTEXT_NAME="contextName"; + // REFERENCES private ConfigurationAdmin configurationAdmin; @@ -66,11 +76,12 @@ public class CmsState implements NodeState, ManagedService { // Standalone services private BitronixTransactionManager transactionManager; private BitronixTransactionSynchronizationRegistry transactionSynchronizationRegistry; - private OsgiJackrabbitRepositoryFactory repositoryFactory; + private NodeRepositoryFactory repositoryFactory; // Security private NodeUserAdmin userAdmin; - private JackrabbitRepositoryServiceFactory repositoryServiceFactory; + private RepositoryServiceFactory repositoryServiceFactory; + private RepositoryService repositoryService; // Deployment private final CmsDeployment nodeDeployment = new CmsDeployment(); @@ -78,29 +89,68 @@ public class CmsState implements NodeState, ManagedService { private boolean cleanState = false; private URI nodeRepoUri = null; + private String hostname; + + public CmsState() { + try { + this.hostname = InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException e) { + log.error("Cannot set hostname", e); + } + } + @Override public void updated(Dictionary properties) throws ConfigurationException { if (properties == null) { + // TODO this should not happen anymore this.cleanState = true; if (log.isTraceEnabled()) log.trace("Clean state"); return; } + String stateUuid = properties.get(NodeConstants.CN).toString(); + String frameworkUuid = KernelUtils.getFrameworkProp(Constants.FRAMEWORK_UUID); + this.cleanState = stateUuid.equals(frameworkUuid); try { if (log.isDebugEnabled()) - log.debug( - "## CMS STARTED " + (cleanState ? " (clean state) " : "") + LangUtils.toJson(properties, true)); + log.debug("## CMS STARTED " + stateUuid + (cleanState ? " (clean state) " : " ") + + LangUtils.toJson(properties, true)); configurationAdmin = bc.getService(bc.getServiceReference(ConfigurationAdmin.class)); + nodeRepoUri = KernelUtils.getOsgiInstanceUri("repos/node"); + + // pre-requisite initI18n(properties); initTrackers(); + // standalone services initTransactionManager(); initRepositoryFactory(); + // UI + initUi(); + // Deployment + initDeployConfigs(properties); initUserAdmin(); initRepositories(properties); initWebServer(); initNodeDeployment(); + + // MetaTypeService metaTypeService = + // bc.getService(bc.getServiceReference(MetaTypeService.class)); + // MetaTypeInformation metaInfo = + // metaTypeService.getMetaTypeInformation(bc.getBundle()); + // String[] pids = metaInfo.getPids(); + // for (String pid : pids) { + // log.debug("MetaType PID : " + pid); + // ObjectClassDefinition ocd = + // metaInfo.getObjectClassDefinition(pid, null); + // log.debug(ocd.getID()); + // for (AttributeDefinition attr : + // ocd.getAttributeDefinitions(ObjectClassDefinition.ALL)) { + // log.debug(attr.getID()); + // } + // } + } catch (Exception e) { throw new CmsException("Cannot get configuration", e); } @@ -108,7 +158,7 @@ public class CmsState implements NodeState, ManagedService { private void initTrackers() { new ServiceTracker(bc, HttpService.class, new PrepareHttpStc()).open(); - new ServiceTracker<>(bc, JackrabbitRepository.class, new JackrabbitrepositoryStc()).open(); + new ServiceTracker<>(bc, RepositoryContext.class, new RepositoryContextStc()).open(); } private void initI18n(Dictionary stateProps) { @@ -140,43 +190,72 @@ public class CmsState implements NodeState, ManagedService { private void initRepositoryFactory() { // TODO rationalise RepositoryFactory - repositoryFactory = new OsgiJackrabbitRepositoryFactory(); - repositoryFactory.setBundleContext(bc); + repositoryFactory = new NodeRepositoryFactory(); // register bc.registerService(RepositoryFactory.class, repositoryFactory, null); } + private void initUi() { + bc.registerService(ApplicationConfiguration.class, new MaintenanceUi(), + LangUtils.init(PROPERTY_CONTEXT_NAME, "system")); + bc.registerService(ApplicationConfiguration.class, new UserUi(), + LangUtils.init(PROPERTY_CONTEXT_NAME, "user")); + } + + private void initDeployConfigs(Dictionary stateProps) throws IOException { + Path deployPath = KernelUtils.getOsgiInstancePath(KernelConstants.DIR_NODE + '/' + KernelConstants.DIR_DEPLOY); + Files.createDirectories(deployPath); + + Path nodeConfigPath = deployPath.resolve(NodeConstants.NODE_REPO_PID + ".properties"); + if (!Files.exists(nodeConfigPath)) { + Dictionary nodeConfig = getNodeConfig(stateProps); + nodeConfig.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, ArgeoJcrConstants.ALIAS_NODE); + nodeConfig.put(RepoConf.labeledUri.name(), nodeRepoUri.toString()); + LangUtils.storeAsProperties(nodeConfig, nodeConfigPath); + } + + if (cleanState) { + try (DirectoryStream ds = Files.newDirectoryStream(deployPath)) { + for (Path path : ds) { + if (Files.isDirectory(path)) {// managed factories + try (DirectoryStream factoryDs = Files.newDirectoryStream(path)) { + for (Path confPath : factoryDs) { + Configuration conf = configurationAdmin + .createFactoryConfiguration(path.getFileName().toString()); + Dictionary props = LangUtils.loadFromProperties(confPath); + conf.update(props); + } + } + } else {// managed services + String pid = path.getFileName().toString(); + pid = pid.substring(0, pid.length() - ".properties".length()); + Configuration conf = configurationAdmin.getConfiguration(pid); + Dictionary props = LangUtils.loadFromProperties(path); + conf.update(props); + } + } + } + } + } + private void initUserAdmin() { userAdmin = new NodeUserAdmin(); // register Dictionary props = userAdmin.currentState(); - props.put(Constants.SERVICE_PID, NodeConstants.NODE_REPO_PID); + props.put(Constants.SERVICE_PID, NodeConstants.NODE_USER_ADMIN_PID); // TODO use ManagedService bc.registerService(UserAdmin.class, userAdmin, props); } private void initRepositories(Dictionary stateProps) throws IOException { - nodeRepoUri = KernelUtils.getOsgiInstanceUri("repos/node"); // register - repositoryServiceFactory = new JackrabbitRepositoryServiceFactory(); + repositoryServiceFactory = new RepositoryServiceFactory(); bc.registerService(ManagedServiceFactory.class, repositoryServiceFactory, LangUtils.init(Constants.SERVICE_PID, NodeConstants.JACKRABBIT_FACTORY_PID)); - if (cleanState) { - Configuration newNodeConf = configurationAdmin - .createFactoryConfiguration(NodeConstants.JACKRABBIT_FACTORY_PID); - Dictionary props = getNodeConfig(stateProps); - if (props == null) { - if (log.isDebugEnabled()) - log.debug("No argeo.node.repo.type=localfs|h2|postgresql|memory" - + " property defined, entering interactive mode..."); - // TODO interactive configuration - return; - } - // props.put(Constants.SERVICE_PID, NodeConstants.NODE_REPO_PID); - props.put(RepoConf.uri.name(), nodeRepoUri.toString()); - newNodeConf.update(props); - } + repositoryService = new RepositoryService(); + Dictionary regProps = LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_REPO_PID); + bc.registerService(LangUtils.names(ManagedService.class, MetaTypeProvider.class), repositoryService, regProps); } private void initWebServer() { @@ -231,15 +310,16 @@ public class CmsState implements NodeState, ManagedService { // Clean hanging Gogo shell thread new GogoShellKiller().start(); - + if (log.isDebugEnabled()) log.debug("## CMS STOPPED"); } private Dictionary getNodeConfig(Dictionary properties) { - Object repoType = properties.get(NodeConstants.NODE_REPO_PROP_PREFIX + RepoConf.type.name()); - if (repoType == null) - return null; + // Object repoType = properties.get(NodeConstants.NODE_REPO_PROP_PREFIX + // + RepoConf.type.name()); + // if (repoType == null) + // return null; Hashtable props = new Hashtable(); for (RepoConf repoConf : RepoConf.values()) { @@ -250,29 +330,30 @@ public class CmsState implements NodeState, ManagedService { return props; } - private class JackrabbitrepositoryStc - implements ServiceTrackerCustomizer { + private class RepositoryContextStc implements ServiceTrackerCustomizer { @Override - public JackrabbitRepository addingService(ServiceReference reference) { - JackrabbitRepository nodeRepo = bc.getService(reference); + public RepositoryContext addingService(ServiceReference reference) { + RepositoryContext nodeRepo = bc.getService(reference); Object repoUri = reference.getProperty(ArgeoJcrConstants.JCR_REPOSITORY_URI); if (repoUri != null && repoUri.equals(nodeRepoUri.toString())) { - nodeDeployment.setDeployedNodeRepository(nodeRepo); + nodeDeployment.setDeployedNodeRepository(nodeRepo.getRepository()); + Dictionary props = LangUtils.init(Constants.SERVICE_PID, + NodeConstants.NODE_DEPLOYMENT_PID); + props.put("uid", nodeRepo.getRootNodeId().toString()); // register - bc.registerService(LangUtils.names(NodeDeployment.class, ManagedService.class), nodeDeployment, - LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_DEPLOYMENT_PID)); + bc.registerService(LangUtils.names(NodeDeployment.class, ManagedService.class), nodeDeployment, props); } return nodeRepo; } @Override - public void modifiedService(ServiceReference reference, JackrabbitRepository service) { + public void modifiedService(ServiceReference reference, RepositoryContext service) { } @Override - public void removedService(ServiceReference reference, JackrabbitRepository service) { + public void removedService(ServiceReference reference, RepositoryContext service) { } } @@ -322,6 +403,10 @@ public class CmsState implements NodeState, ManagedService { return locales; } + public String getHostname() { + return hostname; + } + /* * STATIC */ diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitNodeType.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitNodeType.java deleted file mode 100644 index f737f8aad..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitNodeType.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.argeo.cms.internal.kernel; - -/** The available Jackrabbit node types */ -public enum JackrabbitNodeType { - NOT_CONFIGURED, h2, postgresql, memory, localfs; -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitRepositoryServiceFactory.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitRepositoryServiceFactory.java deleted file mode 100644 index d10b78baf..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitRepositoryServiceFactory.java +++ /dev/null @@ -1,254 +0,0 @@ -package org.argeo.cms.internal.kernel; - -import java.io.File; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Dictionary; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -import javax.jcr.RepositoryException; - -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.argeo.ArgeoException; -import org.argeo.cms.CmsException; -import org.argeo.jackrabbit.JackrabbitNodeType; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.ArgeoJcrException; -import org.argeo.node.RepoConf; -import org.argeo.util.LangUtils; -import org.osgi.framework.BundleContext; -import org.osgi.framework.Constants; -import org.osgi.framework.FrameworkUtil; -import org.osgi.service.cm.ConfigurationAdmin; -import org.osgi.service.cm.ConfigurationException; -import org.osgi.service.cm.ManagedServiceFactory; -import org.xml.sax.InputSource; - -public class JackrabbitRepositoryServiceFactory implements ManagedServiceFactory { - private final static Log log = LogFactory.getLog(JackrabbitRepositoryServiceFactory.class); - private final BundleContext bc = FrameworkUtil.getBundle(JackrabbitRepositoryServiceFactory.class) - .getBundleContext(); - - // Node - final static String REPO_TYPE = "repoType"; - - private Map repositories = new HashMap(); - - @Override - public String getName() { - return "Jackrabbit repository service factory"; - } - - @Override - public void updated(String pid, Dictionary properties) throws ConfigurationException { - if (repositories.containsKey(pid)) - throw new ArgeoException("Already a repository registered for " + pid); - - if (properties == null) - return; - - if (repositories.containsKey(pid)) { - log.warn("Ignore update of Jackrabbit repository " + pid); - return; - } - - try { - RepositoryContext repositoryContext = createNode(properties); - repositories.put(pid, repositoryContext); - Dictionary props = LangUtils.init(Constants.SERVICE_PID, pid); - props.put(ArgeoJcrConstants.JCR_REPOSITORY_URI, properties.get(RepoConf.uri.name())); - bc.registerService(JackrabbitRepository.class, repositoryContext.getRepository(), props); - } catch (Exception e) { - throw new ArgeoException("Cannot create Jackrabbit repository " + pid, e); - } - - } - - @Override - public void deleted(String pid) { - RepositoryContext repositoryContext = repositories.remove(pid); - repositoryContext.getRepository().shutdown(); - if (log.isDebugEnabled()) - log.debug("Deleted repository " + pid); - } - - public void shutdown() { - for (String pid : repositories.keySet()) { - try { - repositories.get(pid).getRepository().shutdown(); - } catch (Exception e) { - log.error("Error when shutting down Jackrabbit repository " + pid, e); - } - } - } - - private RepositoryConfig getConfiguration(Dictionary properties) throws RepositoryException { - JackrabbitNodeType type = JackrabbitNodeType.valueOf(prop(properties, RepoConf.type).toString()); - 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 = getConfigurationProperties(type, properties); - RepositoryConfig repositoryConfig = RepositoryConfig.create(config, jackrabbitVars); - return repositoryConfig; - } finally { - IOUtils.closeQuietly(in); - } - } - - private Properties getConfigurationProperties(JackrabbitNodeType type, Dictionary properties) { - Properties props = new Properties(); - keys: for (Enumeration keys = properties.keys(); keys.hasMoreElements();) { - String key = keys.nextElement(); - if (key.equals(ConfigurationAdmin.SERVICE_FACTORYPID) || key.equals(Constants.SERVICE_PID)) - continue keys; - String value = prop(properties, RepoConf.valueOf(key)); - if (value != null) - props.put(key, value); - } - - // home - // File osgiInstanceDir = getOsgiInstanceDir(); - String homeUri = props.getProperty(RepoConf.uri.name()); - Path homePath; - try { - homePath = Paths.get(new URI(homeUri)); - } catch (URISyntaxException e) { - throw new CmsException("Invalid repository home URI", e); - } - // File homeDir = new File(osgiInstanceDir, "repos/node"); - File homeDir = homePath.toFile(); - 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(Properties props, RepoConf key, String def) { - Object value = props.get(key.name()); - if (value == null) - value = def; - if (value == null) - value = key.getDefault(); - if (value != null) - props.put(key.name(), value.toString()); - } - - private void setProp(Properties props, RepoConf key) { - setProp(props, key, null); - } - - private String prop(Dictionary properties, RepoConf key) { - Object value = properties.get(key.name()); - if (value == null) - return key.getDefault() != null ? key.getDefault().toString() : null; - else - return value.toString(); - } - - private RepositoryContext createNode(Dictionary properties) throws RepositoryException { - RepositoryConfig repositoryConfig = getConfiguration(properties); - RepositoryContext repositoryContext = createJackrabbitRepository(repositoryConfig); - RepositoryImpl repository = repositoryContext.getRepository(); - - // cache - Object maxCacheMbStr = prop(properties, RepoConf.maxCacheMB); - if (maxCacheMbStr != null) { - Integer maxCacheMB = Integer.parseInt(maxCacheMbStr.toString()); - CacheManager cacheManager = repository.getCacheManager(); - cacheManager.setMaxMemory(maxCacheMB * 1024l * 1024l); - cacheManager.setMaxMemoryPerCache((maxCacheMB / 4) * 1024l * 1024l); - } - - return repositoryContext; - } - - private RepositoryContext createJackrabbitRepository(RepositoryConfig repositoryConfig) throws RepositoryException { - ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(JackrabbitRepositoryServiceFactory.class.getClassLoader()); - try { - 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; - } finally { - Thread.currentThread().setContextClassLoader(currentContextCl); - } - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitType.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitType.java new file mode 100644 index 000000000..b10fd4e49 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitType.java @@ -0,0 +1,6 @@ +package org.argeo.cms.internal.kernel; + +/** The available Jackrabbit node types */ +public enum JackrabbitType { + localfs, h2, postgresql, postgresql_ds, memory; +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java index 65e38912c..7f0197412 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java @@ -54,7 +54,6 @@ import org.argeo.ArgeoException; import org.argeo.ArgeoLogger; import org.argeo.cms.CmsException; import org.argeo.cms.maintenance.MaintenanceUi; -import org.argeo.jackrabbit.OsgiJackrabbitRepositoryFactory; import org.argeo.jcr.ArgeoJcrConstants; import org.argeo.jcr.JcrUtils; import org.argeo.node.DataModelNamespace; @@ -106,6 +105,7 @@ import bitronix.tm.TransactionManagerServices; *
  • OS access
  • * */ +@Deprecated final class Kernel implements KernelHeader, KernelConstants { /* * SERVICE REFERENCES @@ -132,7 +132,7 @@ final class Kernel implements KernelHeader, KernelConstants { private NodeLogger logger; private BitronixTransactionManager transactionManager; private BitronixTransactionSynchronizationRegistry transactionSynchronizationRegistry; - private OsgiJackrabbitRepositoryFactory repositoryFactory; + private NodeRepositoryFactory repositoryFactory; private Repository repository; private NodeUserAdmin userAdmin; @@ -499,7 +499,7 @@ final class Kernel implements KernelHeader, KernelConstants { // Initialise services initTransactionManager(); - JackrabbitRepositoryServiceFactory jrsf = new JackrabbitRepositoryServiceFactory(); + RepositoryServiceFactory jrsf = new RepositoryServiceFactory(); String[] clazzes = { ManagedServiceFactory.class.getName() }; Hashtable serviceProps = new Hashtable(); serviceProps.put(Constants.SERVICE_PID, ArgeoJcrConstants.JACKRABBIT_REPO_FACTORY_PID); @@ -549,11 +549,11 @@ final class Kernel implements KernelHeader, KernelConstants { JackrabbitRepository nodeRepo = bc.getService(reference); // new // JackrabbitDataModel(bc).prepareDataModel(nodeRepo); - prepareDataModel(KernelUtils.openAdminSession( nodeRepo)); + prepareDataModel(KernelUtils.openAdminSession(nodeRepo)); // repository = (JackrabbitRepository) // bc.getService(repositoryReg.getReference()); - repository = new HomeRepository( nodeRepo); + repository = new HomeRepository(nodeRepo); Hashtable regProps = new Hashtable(); regProps.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, ArgeoJcrConstants.ALIAS_NODE); repositoryReg = (ServiceRegistration) bc.registerService(Repository.class, @@ -562,8 +562,8 @@ final class Kernel implements KernelHeader, KernelConstants { // if (repository == null) // repository = new NodeRepository(); if (repositoryFactory == null) { - repositoryFactory = new OsgiJackrabbitRepositoryFactory(); - repositoryFactory.setBundleContext(bc); + repositoryFactory = new NodeRepositoryFactory(); + // repositoryFactory.setBundleContext(bc); repositoryFactoryReg = bc.registerService(RepositoryFactory.class, repositoryFactory, null); } userAdmin = new NodeUserAdmin(transactionManager, repository); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java index fa746521f..344a154c5 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java @@ -9,6 +9,7 @@ public interface KernelConstants { // Directories final static String DIR_NODE = "node"; + final static String DIR_DEPLOY = "deploy"; final static String DIR_TRANSACTIONS = "transactions"; final static String DIR_PKI = "pki"; final static String DIR_PKI_PRIVATE = DIR_PKI + "/private"; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java index 9b220f20a..49f8c20a5 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java @@ -4,6 +4,8 @@ import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.security.PrivilegedAction; import java.util.Dictionary; import java.util.Enumeration; @@ -65,25 +67,25 @@ class KernelUtils implements KernelConstants { .getAbsoluteFile(); } + static Path getOsgiInstancePath(String relativePath) { + return Paths.get(getOsgiInstanceUri(relativePath)); + } + static URI getOsgiInstanceUri(String relativePath) { String osgiInstanceBaseUri = getFrameworkProp(OSGI_INSTANCE_AREA); - try { - return new URI(osgiInstanceBaseUri + (relativePath != null ? relativePath : "")); - } catch (URISyntaxException e) { - throw new CmsException("Cannot get OSGi instance URI for " + relativePath, e); - } + return safeUri(osgiInstanceBaseUri + (relativePath != null ? relativePath : "")); } - static String getOsgiInstancePath(String relativePath) { - try { - if (relativePath == null) - return getOsgiInstanceDir().getCanonicalPath(); - else - return new File(getOsgiInstanceDir(), relativePath).getCanonicalPath(); - } catch (IOException e) { - throw new CmsException("Cannot get instance path for " + relativePath, e); - } - } +// static String getOsgiInstancePath(String relativePath) { +// try { +// if (relativePath == null) +// return getOsgiInstanceDir().getCanonicalPath(); +// else +// return new File(getOsgiInstanceDir(), relativePath).getCanonicalPath(); +// } catch (IOException e) { +// throw new CmsException("Cannot get instance path for " + relativePath, e); +// } +// } static File getOsgiConfigurationFile(String relativePath) { try { @@ -118,26 +120,6 @@ class KernelUtils implements KernelConstants { } } - // @Deprecated - // static void anonymousLogin(AuthenticationManager authenticationManager) { - // try { - // List anonAuthorities = Collections - // .singletonList(new GrantedAuthorityPrincipal( - // KernelHeader.ROLE_ANONYMOUS)); - // UserDetails anonUser = new User(KernelHeader.USERNAME_ANONYMOUS, - // "", true, true, true, true, anonAuthorities); - // AnonymousAuthenticationToken anonToken = new - // AnonymousAuthenticationToken( - // DEFAULT_SECURITY_KEY, anonUser, anonAuthorities); - // Authentication authentication = authenticationManager - // .authenticate(anonToken); - // SecurityContextHolder.getContext() - // .setAuthentication(authentication); - // } catch (Exception e) { - // throw new CmsException("Cannot authenticate", e); - // } - // } - // HTTP static void logRequestHeaders(Log log, HttpServletRequest request) { if (!log.isDebugEnabled()) @@ -213,6 +195,16 @@ class KernelUtils implements KernelConstants { private static BundleContext getBundleContext() { return getBundleContext(KernelUtils.class); } + + private static URI safeUri(String uri){ + if(uri==null) + throw new CmsException("URI cannot be null"); + try { + return new URI(uri); + } catch (URISyntaxException e) { + throw new CmsException("Dadly formatted URI "+uri, e); + } + } private KernelUtils() { diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeRepositoryFactory.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeRepositoryFactory.java new file mode 100644 index 000000000..74a9208c1 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeRepositoryFactory.java @@ -0,0 +1,61 @@ +/* + * 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. + */ +package org.argeo.cms.internal.kernel; + +import java.util.Collection; + +import javax.jcr.Repository; + +import org.argeo.jackrabbit.JackrabbitRepositoryFactory; +import org.argeo.jcr.ArgeoJcrException; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; + +/** + * OSGi-aware Jackrabbit repository factory which can retrieve/publish + * {@link Repository} as OSGi services. + */ +class NodeRepositoryFactory extends JackrabbitRepositoryFactory { + private final BundleContext bundleContext = FrameworkUtil.getBundle(getClass()).getBundleContext(); + + @Override + protected Repository getRepositoryByAlias(String alias) { + try { + Collection> srs = bundleContext.getServiceReferences(Repository.class, + "(" + JCR_REPOSITORY_ALIAS + "=" + alias + ")"); + if (srs.size() == 0) + throw new ArgeoJcrException("No repository with alias " + alias + " found in OSGi registry"); + else if (srs.size() > 1) + throw new ArgeoJcrException( + srs.size() + " repositories with alias " + alias + " found in OSGi registry"); + return bundleContext.getService(srs.iterator().next()); + } catch (InvalidSyntaxException e) { + throw new ArgeoJcrException("Cannot find repository with alias " + alias, e); + } + } + +// private void publish(String alias, Repository repository, Properties properties) { +// if (bundleContext != null) { +// // do not modify reference +// Hashtable props = new Hashtable(); +// props.putAll(props); +// props.put(JCR_REPOSITORY_ALIAS, alias); +// bundleContext.registerService(Repository.class.getName(), repository, props); +// } +// } +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java index 87ba07024..94579be18 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java @@ -137,7 +137,8 @@ class NodeSecurity implements KernelConstants { try { keyStoreFile.getParentFile().mkdirs(); KeyStore keyStore = PkiUtils.getKeyStore(keyStoreFile, ksPwd); - PkiUtils.generateSelfSignedCertificate(keyStore, new X500Principal(AuthConstants.ROLE_KERNEL), keyPwd); + PkiUtils.generateSelfSignedCertificate(keyStore, new X500Principal(AuthConstants.ROLE_KERNEL), 1024, + keyPwd); PkiUtils.saveKeyStore(keyStoreFile, ksPwd, keyStore); if (log.isDebugEnabled()) log.debug("Created keystore " + keyStoreFile); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/PkiUtils.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/PkiUtils.java index f36fc89f5..67f8f01c6 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/PkiUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/PkiUtils.java @@ -35,10 +35,10 @@ class PkiUtils { } public static X509Certificate generateSelfSignedCertificate(KeyStore keyStore, X500Principal x500Principal, - char[] keyPassword) { + int keySize, char[] keyPassword) { try { KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", SECURITY_PROVIDER); - kpGen.initialize(1024, new SecureRandom()); + kpGen.initialize(keySize, new SecureRandom()); KeyPair pair = kpGen.generateKeyPair(); Date notBefore = new Date(System.currentTimeMillis() - 10000); Date notAfter = new Date(System.currentTimeMillis() + 24L * 3600 * 1000); @@ -85,4 +85,75 @@ class PkiUtils { } } + public static void main(String[] args) { + final String ALGORITHM = "RSA"; + final String provider = "BC"; + SecureRandom secureRandom = new SecureRandom(); + long begin = System.currentTimeMillis(); + for (int i = 512; i < 1024; i = i + 2) { + try { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM,provider); + keyGen.initialize(i, secureRandom); + keyGen.generateKeyPair(); + } catch (Exception e) { + System.err.println(i + " : " + e.getMessage()); + } + } + System.out.println( (System.currentTimeMillis() - begin) + " ms"); + +// // String text = "a"; +// String text = "testtesttesttesttesttesttesttesttesttesttesttesttesttesttest"; +// try { +// System.out.println(text); +// PrivateKey privateKey; +// PublicKey publicKey; +// char[] password = "changeit".toCharArray(); +// String alias = "CN=test"; +// KeyStore keyStore = KeyStore.getInstance("pkcs12"); +// File p12file = new File("test.p12"); +// p12file.delete(); +// if (!p12file.exists()) { +// keyStore.load(null); +// generateSelfSignedCertificate(keyStore, new X500Principal(alias), 513, password); +// try (OutputStream out = new FileOutputStream(p12file)) { +// keyStore.store(out, password); +// } +// } +// try (InputStream in = new FileInputStream(p12file)) { +// keyStore.load(in, password); +// privateKey = (PrivateKey) keyStore.getKey(alias, password); +// publicKey = keyStore.getCertificateChain(alias)[0].getPublicKey(); +// } +// // KeyPair key; +// // final KeyPairGenerator keyGen = +// // KeyPairGenerator.getInstance(ALGORITHM); +// // keyGen.initialize(4096, new SecureRandom()); +// // long begin = System.currentTimeMillis(); +// // key = keyGen.generateKeyPair(); +// // System.out.println((System.currentTimeMillis() - begin) + " ms"); +// // keyStore.load(null); +// // keyStore.setKeyEntry("test", key.getPrivate(), password, null); +// // try(OutputStream out=new FileOutputStream(p12file)) { +// // keyStore.store(out, password); +// // } +// // privateKey = key.getPrivate(); +// // publicKey = key.getPublic(); +// +// Cipher encrypt = Cipher.getInstance(ALGORITHM); +// encrypt.init(Cipher.ENCRYPT_MODE, publicKey); +// byte[] encrypted = encrypt.doFinal(text.getBytes()); +// String encryptedBase64 = Base64.getEncoder().encodeToString(encrypted); +// System.out.println(encryptedBase64); +// byte[] encryptedFromBase64 = Base64.getDecoder().decode(encryptedBase64); +// +// Cipher decrypt = Cipher.getInstance(ALGORITHM); +// decrypt.init(Cipher.DECRYPT_MODE, privateKey); +// byte[] decrypted = decrypt.doFinal(encryptedFromBase64); +// System.out.println(new String(decrypted)); +// } catch (Exception e) { +// e.printStackTrace(); +// } + + } + } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryBuilder.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryBuilder.java new file mode 100644 index 000000000..94b8c051e --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryBuilder.java @@ -0,0 +1,201 @@ +package org.argeo.cms.internal.kernel; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.Properties; +import java.util.UUID; + +import javax.jcr.RepositoryException; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.core.RepositoryContext; +import org.apache.jackrabbit.core.RepositoryImpl; +import org.apache.jackrabbit.core.cache.CacheManager; +import org.apache.jackrabbit.core.config.RepositoryConfig; +import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; +import org.argeo.cms.CmsException; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.jcr.ArgeoJcrException; +import org.argeo.node.RepoConf; +import org.osgi.framework.Constants; +import org.osgi.service.cm.ConfigurationAdmin; +import org.xml.sax.InputSource; + +/** Can interpret properties in order to create an actual JCR repository. */ +class RepositoryBuilder { + private final static Log log = LogFactory.getLog(RepositoryBuilder.class); + + RepositoryContext createRepositoryContext(Dictionary properties) throws RepositoryException { + RepositoryConfig repositoryConfig = createRepositoryConfig(properties); + RepositoryContext repositoryContext = createJackrabbitRepository(repositoryConfig); + RepositoryImpl repository = repositoryContext.getRepository(); + + // cache + Object maxCacheMbStr = prop(properties, RepoConf.maxCacheMB); + if (maxCacheMbStr != null) { + Integer maxCacheMB = Integer.parseInt(maxCacheMbStr.toString()); + CacheManager cacheManager = repository.getCacheManager(); + cacheManager.setMaxMemory(maxCacheMB * 1024l * 1024l); + cacheManager.setMaxMemoryPerCache((maxCacheMB / 4) * 1024l * 1024l); + } + + return repositoryContext; + } + + RepositoryConfig createRepositoryConfig(Dictionary properties) throws RepositoryException { + JackrabbitType type = JackrabbitType.valueOf(prop(properties, RepoConf.type).toString()); + 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 = getConfigurationProperties(type, properties); + RepositoryConfig repositoryConfig = RepositoryConfig.create(config, jackrabbitVars); + return repositoryConfig; + } finally { + IOUtils.closeQuietly(in); + } + } + + private Properties getConfigurationProperties(JackrabbitType type, Dictionary properties) { + Properties props = new Properties(); + keys: for (Enumeration keys = properties.keys(); keys.hasMoreElements();) { + String key = keys.nextElement(); + if (key.equals(ConfigurationAdmin.SERVICE_FACTORYPID) || key.equals(Constants.SERVICE_PID) + || key.equals(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS)) + continue keys; + String value = prop(properties, RepoConf.valueOf(key)); + if (value != null) + props.put(key, value); + } + + // home + String homeUri = props.getProperty(RepoConf.labeledUri.name()); + Path homePath; + try { + homePath = Paths.get(new URI(homeUri)).toAbsolutePath(); + } catch (URISyntaxException e) { + throw new CmsException("Invalid repository home URI", e); + } + Path rootUuidPath = homePath.resolve("repository/meta/rootUUID"); + if (!Files.exists(rootUuidPath)) { + try { + Files.createDirectories(rootUuidPath.getParent()); + Files.write(rootUuidPath, UUID.randomUUID().toString().getBytes()); + } catch (IOException e) { + log.error("Could not set rootUUID", e); + } + } + File homeDir = homePath.toFile(); + homeDir.mkdirs(); + // home cannot be overridden + props.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, homePath.toString()); + + // common + setProp(props, RepoConf.defaultWorkspace); + setProp(props, RepoConf.maxPoolSize); + // Jackrabbit defaults + setProp(props, RepoConf.bundleCacheMB); + // See http://wiki.apache.org/jackrabbit/Search + setProp(props, RepoConf.extractorPoolSize); + setProp(props, RepoConf.searchCacheSize); + setProp(props, RepoConf.maxVolatileIndexSize); + + // specific + String dburl; + switch (type) { + case h2: + dburl = "jdbc:h2:" + 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(Properties props, RepoConf key, String def) { + Object value = props.get(key.name()); + if (value == null) + value = def; + if (value == null) + value = key.getDefault(); + if (value != null) + props.put(key.name(), value.toString()); + } + + private void setProp(Properties props, RepoConf key) { + setProp(props, key, null); + } + + private String prop(Dictionary properties, RepoConf key) { + Object value = properties.get(key.name()); + if (value == null) + return key.getDefault() != null ? key.getDefault().toString() : null; + else + return value.toString(); + } + + private RepositoryContext createJackrabbitRepository(RepositoryConfig repositoryConfig) throws RepositoryException { + ClassLoader currentContextCl = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(RepositoryBuilder.class.getClassLoader()); + try { + long begin = System.currentTimeMillis(); + // + // Actual repository creation + // + RepositoryContext repositoryContext = RepositoryContext.create(repositoryConfig); + + double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; + if (log.isTraceEnabled()) + log.trace( + "Created Jackrabbit repository in " + duration + " s, home: " + repositoryConfig.getHomeDir()); + + return repositoryContext; + } finally { + Thread.currentThread().setContextClassLoader(currentContextCl); + } + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryService.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryService.java new file mode 100644 index 000000000..ed8be17ea --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryService.java @@ -0,0 +1,152 @@ +package org.argeo.cms.internal.kernel; + +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.List; +import java.util.Locale; + +import org.apache.jackrabbit.core.RepositoryContext; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.node.RepoConf; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.cm.ManagedService; +import org.osgi.service.metatype.MetaTypeProvider; +import org.osgi.service.metatype.ObjectClassDefinition; + +public class RepositoryService implements ManagedService, MetaTypeProvider { + private BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext(); + // private RepositoryContext repositoryContext = null; + private ServiceRegistration repositoryContextReg; + + @Override + public synchronized void updated(Dictionary properties) throws ConfigurationException { + if (properties == null) + return; + + if (repositoryContextReg != null) { + shutdown(); + } + +// for (String key : LangUtils.keys(properties)) { +// Object value = properties.get(key); +// System.out.println(key + " : " + value.getClass().getName()); +// } + + try { + RepositoryBuilder repositoryBuilder = new RepositoryBuilder(); + RepositoryContext repositoryContext = repositoryBuilder.createRepositoryContext(properties); + Dictionary props = new Hashtable<>(); + props.put(ArgeoJcrConstants.JCR_REPOSITORY_URI, properties.get(RepoConf.labeledUri.name())); + Object cn = properties.get(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS); + if (cn != null) { + props.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, cn); + } + repositoryContextReg = bc.registerService(RepositoryContext.class, repositoryContext, props); + } catch (Exception e) { + throw new ArgeoException("Cannot create Jackrabbit repository", e); + } + + } + + public synchronized void shutdown() { + if (repositoryContextReg == null) + return; + RepositoryContext repositoryContext = bc.getService(repositoryContextReg.getReference()); + repositoryContext.getRepository().shutdown(); + repositoryContextReg.unregister(); + repositoryContextReg = null; + } + + /* + * METATYPE + */ + @Override + public ObjectClassDefinition getObjectClassDefinition(String id, String locale) { + return new RepoConf.OCD(locale); + // return new EnumOCD<>(RepoConf.class); + // return new JcrRepositoryOCD(locale); + } + + @Override + public String[] getLocales() { + // TODO optimize? + List locales = Activator.getNodeState().getLocales(); + String[] res = new String[locales.size()]; + for (int i = 0; i < locales.size(); i++) + res[i] = locales.get(i).toString(); + return res; + } + + /* + * JACKRABBIT REPOSITORY + */ + + // private RepositoryImpl repo() { + // return repositoryContext.getRepository(); + // } + // + // @Override + // public String[] getDescriptorKeys() { + // return repo().getDescriptorKeys(); + // } + // + // @Override + // public boolean isStandardDescriptor(String key) { + // return repo().isStandardDescriptor(key); + // } + // + // @Override + // public boolean isSingleValueDescriptor(String key) { + // return repo().isSingleValueDescriptor(key); + // } + // + // @Override + // public Value getDescriptorValue(String key) { + // return repo().getDescriptorValue(key); + // } + // + // @Override + // public Value[] getDescriptorValues(String key) { + // return repo().getDescriptorValues(key); + // } + // + // @Override + // public String getDescriptor(String key) { + // return repo().getDescriptor(key); + // } + // + // @Override + // public Session login(Credentials credentials, String workspaceName) + // throws LoginException, NoSuchWorkspaceException, RepositoryException { + // return repo().login(); + // } + // + // @Override + // public Session login(Credentials credentials) throws LoginException, + // RepositoryException { + // return repo().login(credentials); + // } + // + // @Override + // public Session login(String workspaceName) throws LoginException, + // NoSuchWorkspaceException, RepositoryException { + // return repo().login(workspaceName); + // } + // + // @Override + // public Session login() throws LoginException, RepositoryException { + // return repo().login(); + // } + // + // @Override + // public Session login(Credentials credentials, String workspaceName, + // Map attributes) + // throws LoginException, NoSuchWorkspaceException, RepositoryException { + // return repo().login(credentials, workspaceName, attributes); + // } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryServiceFactory.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryServiceFactory.java new file mode 100644 index 000000000..a4e3a9bb8 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/RepositoryServiceFactory.java @@ -0,0 +1,75 @@ +package org.argeo.cms.internal.kernel; + +import java.util.Dictionary; +import java.util.HashMap; +import java.util.Map; + +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.argeo.ArgeoException; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.node.RepoConf; +import org.argeo.util.LangUtils; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.FrameworkUtil; +import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.cm.ManagedServiceFactory; + +class RepositoryServiceFactory implements ManagedServiceFactory { + private final static Log log = LogFactory.getLog(RepositoryServiceFactory.class); + private final BundleContext bc = FrameworkUtil.getBundle(RepositoryServiceFactory.class).getBundleContext(); + + private Map repositories = new HashMap(); + + @Override + public String getName() { + return "Jackrabbit repository service factory"; + } + + @Override + public void updated(String pid, Dictionary properties) throws ConfigurationException { + if (repositories.containsKey(pid)) + throw new ArgeoException("Already a repository registered for " + pid); + + if (properties == null) + return; + + if (repositories.containsKey(pid)) { + log.warn("Ignore update of Jackrabbit repository " + pid); + return; + } + + try { + RepositoryBuilder repositoryBuilder = new RepositoryBuilder(); + RepositoryContext repositoryContext = repositoryBuilder.createRepositoryContext(properties); + repositories.put(pid, repositoryContext); + Dictionary props = LangUtils.init(Constants.SERVICE_PID, pid); + props.put(ArgeoJcrConstants.JCR_REPOSITORY_URI, properties.get(RepoConf.labeledUri.name())); + bc.registerService(JackrabbitRepository.class, repositoryContext.getRepository(), props); + } catch (Exception e) { + throw new ArgeoException("Cannot create Jackrabbit repository " + pid, e); + } + + } + + @Override + public void deleted(String pid) { + RepositoryContext repositoryContext = repositories.remove(pid); + repositoryContext.getRepository().shutdown(); + if (log.isDebugEnabled()) + log.debug("Deleted repository " + pid); + } + + public void shutdown() { + for (String pid : repositories.keySet()) { + try { + repositories.get(pid).getRepository().shutdown(); + } catch (Exception e) { + log.error("Error when shutting down Jackrabbit repository " + pid, e); + } + } + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg b/org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg index 2bb1ab481..88b2cd8e4 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg @@ -13,6 +13,10 @@ DATA_ADMIN { org.argeo.cms.auth.DataAdminLoginModule requisite; }; +SYSTEM { + org.argeo.cms.auth.DataAdminLoginModule requisite; +}; + KERNEL { org.argeo.cms.internal.auth.KernelLoginModule requisite; }; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-h2.xml b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-h2.xml index 822b1fa25..05267621f 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-h2.xml +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-h2.xml @@ -5,11 +5,11 @@ - - - + + + - + @@ -25,7 +25,7 @@ + defaultWorkspace="${defaultWorkspace}" /> @@ -36,13 +36,13 @@ class="org.apache.jackrabbit.core.persistence.pool.H2PersistenceManager"> - + - - - + + + - + - - - + + + diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-localfs.xml b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-localfs.xml index 3ab8a2906..3d2470863 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-localfs.xml +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-localfs.xml @@ -11,20 +11,20 @@ + defaultWorkspace="${defaultWorkspace}" /> - + - - - + + + - + - - - + + + diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-memory.xml b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-memory.xml index 3215969e8..ecee5bdad 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-memory.xml +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-memory.xml @@ -6,21 +6,21 @@ + defaultWorkspace="${defaultWorkspace}" configRootPath="/workspaces" /> - + - - - + + + @@ -31,7 +31,7 @@ - + @@ -40,9 +40,9 @@ - - - + + + diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-postgresql-ds.xml b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-postgresql-ds.xml index c8e077e21..07a0d0428 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-postgresql-ds.xml +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-postgresql-ds.xml @@ -5,11 +5,11 @@ - - - + + + - + @@ -25,7 +25,7 @@ + defaultWorkspace="${defaultWorkspace}" /> @@ -36,13 +36,13 @@ class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager"> - + - - - + + + - + - - - + + + diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-postgresql.xml b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-postgresql.xml index 5d4b60fba..967782820 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-postgresql.xml +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-postgresql.xml @@ -5,11 +5,11 @@ - - - + + + - + @@ -22,7 +22,7 @@ + defaultWorkspace="${defaultWorkspace}" /> @@ -33,13 +33,13 @@ class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager"> - + - - - + + + - + - - - + + + diff --git a/org.argeo.cms/src/org/argeo/cms/maintenance/AbstractOsgiComposite.java b/org.argeo.cms/src/org/argeo/cms/maintenance/AbstractOsgiComposite.java new file mode 100644 index 000000000..2494d90c3 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/maintenance/AbstractOsgiComposite.java @@ -0,0 +1,43 @@ +package org.argeo.cms.maintenance; + +import java.util.Collection; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.cms.util.CmsUtils; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; + +abstract class AbstractOsgiComposite extends Composite { + private static final long serialVersionUID = -4097415973477517137L; + protected final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext(); + protected final Log log = LogFactory.getLog(getClass()); + + public AbstractOsgiComposite(Composite parent, int style) { + super(parent, style); + parent.setLayout(CmsUtils.noSpaceGridLayout()); + setLayout(CmsUtils.noSpaceGridLayout()); + setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); + initUi(style); + } + + protected abstract void initUi(int style); + + protected T getService(Class clazz) { + return bc.getService(bc.getServiceReference(clazz)); + } + + protected Collection> getServiceReferences(Class clazz, String filter) { + try { + return bc.getServiceReferences(clazz, filter); + } catch (InvalidSyntaxException e) { + throw new IllegalArgumentException("Filter " + filter + " is invalid", e); + } + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/maintenance/ConnectivityDeploymentUi.java b/org.argeo.cms/src/org/argeo/cms/maintenance/ConnectivityDeploymentUi.java new file mode 100644 index 000000000..f4f3079b6 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/maintenance/ConnectivityDeploymentUi.java @@ -0,0 +1,48 @@ +package org.argeo.cms.maintenance; + +import org.argeo.cms.util.CmsUtils; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.osgi.framework.ServiceReference; +import org.osgi.service.http.HttpService; +import org.osgi.service.useradmin.UserAdmin; + +class ConnectivityDeploymentUi extends AbstractOsgiComposite { + private static final long serialVersionUID = 590221539553514693L; + + public ConnectivityDeploymentUi(Composite parent, int style) { + super(parent, style); + } + + @Override + protected void initUi(int style) { + StringBuffer text = new StringBuffer(); + text.append("Provided Servers
    "); + + ServiceReference userAdminRef = bc.getServiceReference(HttpService.class); + if (userAdminRef != null) { + // FIXME use constants + Object httpPort = userAdminRef.getProperty("http.port"); + Object httpsPort = userAdminRef.getProperty("https.port"); + if (httpPort != null) + text.append("http ").append(httpPort).append("
    "); + if (httpsPort != null) + text.append("https ").append(httpsPort).append("
    "); + + } + + text.append("
    "); + text.append("Referenced Servers
    "); + + Label label = new Label(this, SWT.NONE); + label.setData(new GridData(SWT.FILL, SWT.FILL, false, false)); + CmsUtils.markup(label); + label.setText(text.toString()); + } + + protected boolean isDeployed() { + return bc.getServiceReference(UserAdmin.class) != null; + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/maintenance/DataDeploymentUi.java b/org.argeo.cms/src/org/argeo/cms/maintenance/DataDeploymentUi.java new file mode 100644 index 000000000..8e0c56431 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/maintenance/DataDeploymentUi.java @@ -0,0 +1,149 @@ +package org.argeo.cms.maintenance; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileStore; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; + +import org.apache.jackrabbit.core.RepositoryContext; +import org.apache.jackrabbit.core.config.RepositoryConfig; +import org.argeo.cms.CmsException; +import org.argeo.cms.internal.kernel.JackrabbitType; +import org.argeo.cms.util.CmsUtils; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.node.NodeConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.osgi.framework.ServiceReference; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; + +class DataDeploymentUi extends AbstractOsgiComposite { + private static final long serialVersionUID = 590221539553514693L; + + public DataDeploymentUi(Composite parent, int style) { + super(parent, style); + } + + @Override + protected void initUi(int style) { + if (isDeployed()) { + initCurrentUi(this); + } else { + initNewUi(this); + } + } + + private void initNewUi(Composite parent) { + try { + ConfigurationAdmin confAdmin = bc.getService(bc.getServiceReference(ConfigurationAdmin.class)); + Configuration[] confs = confAdmin.listConfigurations( + "(" + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + NodeConstants.JACKRABBIT_FACTORY_PID + ")"); + if (confs == null || confs.length == 0) { + Group buttonGroup = new Group(parent, SWT.NONE); + buttonGroup.setText("Repository Type"); + buttonGroup.setLayout(new GridLayout(2, true)); + buttonGroup.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + + SelectionListener selectionListener = new SelectionAdapter() { + private static final long serialVersionUID = 6247064348421088092L; + + public void widgetSelected(SelectionEvent event) { + Button radio = (Button) event.widget; + if (!radio.getSelection()) + return; + log.debug(event); + JackrabbitType nodeType = (JackrabbitType) radio.getData(); + if (log.isDebugEnabled()) + log.debug(" selected = " + nodeType.name()); + }; + }; + + for (JackrabbitType nodeType : JackrabbitType.values()) { + Button radio = new Button(buttonGroup, SWT.RADIO); + radio.setText(nodeType.name()); + radio.setData(nodeType); + if (nodeType.equals(JackrabbitType.localfs)) + radio.setSelection(true); + radio.addSelectionListener(selectionListener); + } + + } else if (confs.length == 1) { + + } else { + throw new CmsException("Multiple repos not yet supported"); + } + } catch (Exception e) { + throw new CmsException("Cannot initialize UI", e); + } + + } + + private void initCurrentUi(Composite parent) { + parent.setLayout(new GridLayout()); + Collection> contexts = getServiceReferences(RepositoryContext.class, + "(" + ArgeoJcrConstants.JCR_REPOSITORY_ALIAS + "=*)"); + StringBuffer text = new StringBuffer(); + text.append("Jackrabbit Repositories
    "); + for (ServiceReference sr : contexts) { + RepositoryContext repositoryContext = bc.getService(sr); + String alias = sr.getProperty(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS).toString(); + String rootNodeId = repositoryContext.getRootNodeId().toString(); + RepositoryConfig repositoryConfig = repositoryContext.getRepositoryConfig(); + Path repoHomePath = new File(repositoryConfig.getHomeDir()).toPath().toAbsolutePath(); + // TODO check data store + + text.append("" + alias + "
    "); + text.append("rootNodeId: " + rootNodeId + "
    "); + try { + FileStore fileStore = Files.getFileStore(repoHomePath); + text.append("partition: " + fileStore.toString() + "
    "); + text.append( + percentUsed(fileStore) + " used (" + humanReadable(fileStore.getUsableSpace()) + " free)
    "); + } catch (IOException e) { + log.error("Cannot check fileStore for " + repoHomePath, e); + } + } + Label label = new Label(parent, SWT.NONE); + label.setData(new GridData(SWT.FILL, SWT.FILL, false, false)); + CmsUtils.markup(label); + label.setText("" + text.toString() + ""); + } + + private String humanReadable(long bytes) { + long mb = bytes / (1024 * 1024); + return mb >= 2048 ? Long.toString(mb / 1024) + " GB" : Long.toString(mb) + " MB"; + } + + private String percentUsed(FileStore fs) throws IOException { + long used = fs.getTotalSpace() - fs.getUnallocatedSpace(); + long percent = used * 100 / fs.getTotalSpace(); + if (log.isTraceEnabled()) { + // output identical to `df -B 1`) + log.trace(fs.getTotalSpace() + "," + used + "," + fs.getUsableSpace()); + } + String span; + if (percent < 80) + span = ""; + else if (percent < 95) + span = ""; + else + span = ""; + return span + percent + "%"; + } + + protected boolean isDeployed() { + return bc.getServiceReference(RepositoryContext.class) != null; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/maintenance/DeploymentEntryPoint.java b/org.argeo.cms/src/org/argeo/cms/maintenance/DeploymentEntryPoint.java new file mode 100644 index 000000000..e21974c35 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/maintenance/DeploymentEntryPoint.java @@ -0,0 +1,94 @@ +package org.argeo.cms.maintenance; + +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import org.argeo.cms.util.CmsUtils; +import org.argeo.node.NodeConstants; +import org.argeo.node.NodeDeployment; +import org.argeo.node.NodeState; +import org.eclipse.rap.rwt.application.AbstractEntryPoint; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; + +class DeploymentEntryPoint extends AbstractEntryPoint { + private static final long serialVersionUID = -881152502968982437L; + private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext(); + + @Override + protected void createContents(Composite parent) { + // parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + if (isDesktop()) { + parent.setLayout(new GridLayout(2, true)); + } else { + // TODO add scrolling + parent.setLayout(new GridLayout(1, true)); + } + + initHighLevelSummary(parent); + + Group securityGroup = createHighLevelGroup(parent, "Security"); + securityGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); + new SecurityDeploymentUi(securityGroup, SWT.NONE); + + Group dataGroup = createHighLevelGroup(parent, "Data"); + dataGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); + new DataDeploymentUi(dataGroup, SWT.NONE); + + Group logGroup = createHighLevelGroup(parent, "Notifications"); + logGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true)); + new LogDeploymentUi(logGroup, SWT.NONE); + + Group connectivityGroup = createHighLevelGroup(parent, "Connectivity"); + new ConnectivityDeploymentUi(connectivityGroup, SWT.NONE); + connectivityGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true)); + + } + + private void initHighLevelSummary(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false); + if (isDesktop()) + gridData.horizontalSpan = 3; + composite.setLayoutData(gridData); + composite.setLayout(new FillLayout()); + + ServiceReference nodeStateRef = bc.getServiceReference(NodeState.class); + if (nodeStateRef == null) + throw new IllegalStateException("No CMS state available"); + NodeState nodeState = bc.getService(nodeStateRef); + ServiceReference nodeDeploymentRef = bc.getServiceReference(NodeDeployment.class); + Label label = new Label(composite, SWT.WRAP); + CmsUtils.markup(label); + if (nodeDeploymentRef == null) { + label.setText("Not yet deployed on
    " + nodeState.getHostname() + "
    , please configure below."); + } else { + Object stateUuid = nodeStateRef.getProperty(NodeConstants.CN); + NodeDeployment nodeDeployment = bc.getService(nodeDeploymentRef); + GregorianCalendar calendar = new GregorianCalendar(); + calendar.setTimeInMillis(nodeDeployment.getAvailableSince()); + calendar.setTimeZone(TimeZone.getDefault()); + label.setText("[" + "" + nodeState.getHostname() + "]# " + "Deployment state " + stateUuid + + ", available since " + calendar.getTime() + ""); + } + } + + private static Group createHighLevelGroup(Composite parent, String text) { + Group group = new Group(parent, SWT.NONE); + group.setText(text); + CmsUtils.markup(group); + return group; + } + + private boolean isDesktop() { + return true; + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/maintenance/LogDeploymentUi.java b/org.argeo.cms/src/org/argeo/cms/maintenance/LogDeploymentUi.java new file mode 100644 index 000000000..8fb96437c --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/maintenance/LogDeploymentUi.java @@ -0,0 +1,74 @@ +package org.argeo.cms.maintenance; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Enumeration; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import org.argeo.cms.util.CmsUtils; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Text; +import org.osgi.service.log.LogEntry; +import org.osgi.service.log.LogListener; +import org.osgi.service.log.LogReaderService; + +class LogDeploymentUi extends AbstractOsgiComposite implements LogListener { + private static final long serialVersionUID = 590221539553514693L; + + private DateFormat dateFormat = new SimpleDateFormat("MMdd HH:mm"); + + private Display display; + private Text logDisplay; + + public LogDeploymentUi(Composite parent, int style) { + super(parent, style); + } + + @Override + protected void initUi(int style) { + LogReaderService logReader = getService(LogReaderService.class); + // FIXME use server push + // logReader.addLogListener(this); + this.display = getDisplay(); + this.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + logDisplay = new Text(this, SWT.WRAP | SWT.MULTI | SWT.READ_ONLY); + logDisplay.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + CmsUtils.markup(logDisplay); + @SuppressWarnings("unchecked") + Enumeration logEntries = (Enumeration) logReader.getLog(); + while (logEntries.hasMoreElements()) + logDisplay.append(printEntry(logEntries.nextElement())); + } + + private String printEntry(LogEntry entry) { + StringBuilder sb = new StringBuilder(); + GregorianCalendar calendar = new GregorianCalendar(TimeZone.getDefault()); + calendar.setTimeInMillis(entry.getTime()); + sb.append(dateFormat.format(calendar.getTime())).append(' '); + sb.append(entry.getMessage()); + sb.append('\n'); + return sb.toString(); + } + + @Override + public void logged(LogEntry entry) { + if (display.isDisposed()) + return; + display.asyncExec(() -> { + if (logDisplay.isDisposed()) + return; + logDisplay.append(printEntry(entry)); + }); + display.wake(); + } + + // @Override + // public void dispose() { + // super.dispose(); + // getService(LogReaderService.class).removeLogListener(this); + // } +} diff --git a/org.argeo.cms/src/org/argeo/cms/maintenance/MaintenanceUi.java b/org.argeo.cms/src/org/argeo/cms/maintenance/MaintenanceUi.java index 49556bc99..538379f06 100644 --- a/org.argeo.cms/src/org/argeo/cms/maintenance/MaintenanceUi.java +++ b/org.argeo.cms/src/org/argeo/cms/maintenance/MaintenanceUi.java @@ -7,7 +7,7 @@ public class MaintenanceUi implements ApplicationConfiguration { @Override public void configure(Application application) { - application.addEntryPoint("/migration", MigrationEntryPoint.class, null); + application.addEntryPoint("/status", DeploymentEntryPoint.class, null); } } diff --git a/org.argeo.cms/src/org/argeo/cms/maintenance/MigrationEntryPoint.java b/org.argeo.cms/src/org/argeo/cms/maintenance/MigrationEntryPoint.java deleted file mode 100644 index e6bae8f56..000000000 --- a/org.argeo.cms/src/org/argeo/cms/maintenance/MigrationEntryPoint.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.argeo.cms.maintenance; - -import org.eclipse.rap.rwt.application.AbstractEntryPoint; -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; - -public class MigrationEntryPoint extends AbstractEntryPoint { - - @Override - protected void createContents(Composite parent) { - new Label(parent, SWT.NONE).setText("Migration"); - } - - - -} diff --git a/org.argeo.cms/src/org/argeo/cms/maintenance/SecurityDeploymentUi.java b/org.argeo.cms/src/org/argeo/cms/maintenance/SecurityDeploymentUi.java new file mode 100644 index 000000000..9fcdaf980 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/maintenance/SecurityDeploymentUi.java @@ -0,0 +1,85 @@ +package org.argeo.cms.maintenance; + +import java.net.URI; + +import org.argeo.cms.util.CmsUtils; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.service.useradmin.Role; +import org.osgi.service.useradmin.UserAdmin; + +class SecurityDeploymentUi extends AbstractOsgiComposite { + private static final long serialVersionUID = 590221539553514693L; + + public SecurityDeploymentUi(Composite parent, int style) { + super(parent, style); + } + + @Override + protected void initUi(int style) { + if (isDeployed()) { + initCurrentUi(this); + } else { + initNewUi(this); + } + } + + private void initNewUi(Composite parent) { + new Label(parent, SWT.NONE).setText("Security is not configured"); + } + + private void initCurrentUi(Composite parent) { + ServiceReference userAdminRef = bc.getServiceReference(UserAdmin.class); + UserAdmin userAdmin = bc.getService(userAdminRef); + StringBuffer text = new StringBuffer(); + text.append("Domains
    "); + domains: for (String key : userAdminRef.getPropertyKeys()) { + if (!key.startsWith("/")) + continue domains; + URI uri; + try { + uri = new URI(key); + } catch (Exception e) { + // ignore non URI keys + continue domains; + } + + String rootDn = uri.getPath().substring(1, uri.getPath().length()); + // FIXME make reading query options more robust, using utils + boolean readOnly = uri.getQuery().equals("readOnly=true"); + if (readOnly) + text.append(""); + else + text.append(""); + + text.append(rootDn); + text.append("
    "); + try { + Role[] roles = userAdmin.getRoles("(dn=*," + rootDn + ")"); + long userCount = 0; + long groupCount = 0; + for (Role role : roles) { + if (role.getType() == Role.USER) + userCount++; + else + groupCount++; + } + text.append(" " + userCount + " users, " + groupCount +" groups.
    "); + } catch (InvalidSyntaxException e) { + log.error("Invalid syntax", e); + } + } + Label label = new Label(parent, SWT.NONE); + label.setData(new GridData(SWT.FILL, SWT.FILL, false, false)); + CmsUtils.markup(label); + label.setText(text.toString()); + } + + protected boolean isDeployed() { + return bc.getServiceReference(UserAdmin.class) != null; + } +} diff --git a/org.argeo.eclipse.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/MaintainedRepositoryElem.java b/org.argeo.eclipse.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/MaintainedRepositoryElem.java index 845c23111..92cd0b1b5 100644 --- a/org.argeo.eclipse.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/MaintainedRepositoryElem.java +++ b/org.argeo.eclipse.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/MaintainedRepositoryElem.java @@ -2,23 +2,20 @@ package org.argeo.eclipse.ui.workbench.internal.jcr.model; import javax.jcr.Repository; -import org.argeo.ArgeoException; import org.argeo.eclipse.ui.TreeParent; -import org.argeo.jcr.MaintainedRepository; -/** Wrap a {@link MaintainedRepository} */ +/** Wrap a MaintainedRepository */ public class MaintainedRepositoryElem extends RepositoryElem { - public MaintainedRepositoryElem(String alias, Repository repository, - TreeParent parent) { + public MaintainedRepositoryElem(String alias, Repository repository, TreeParent parent) { super(alias, repository, parent); - if (!(repository instanceof MaintainedRepository)) { - throw new ArgeoException("Repository " + alias - + " is not amiantained repository"); - } + // if (!(repository instanceof MaintainedRepository)) { + // throw new ArgeoException("Repository " + alias + // + " is not amiantained repository"); + // } } - protected MaintainedRepository getMaintainedRepository() { - return (MaintainedRepository) getRepository(); - } + // protected MaintainedRepository getMaintainedRepository() { + // return (MaintainedRepository) getRepository(); + // } } diff --git a/org.argeo.eclipse.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RepositoriesElem.java b/org.argeo.eclipse.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RepositoriesElem.java index 984d01b5f..073754487 100644 --- a/org.argeo.eclipse.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RepositoriesElem.java +++ b/org.argeo.eclipse.ui.workbench/src/org/argeo/eclipse/ui/workbench/internal/jcr/model/RepositoriesElem.java @@ -28,7 +28,6 @@ import org.argeo.ArgeoException; import org.argeo.eclipse.ui.TreeParent; import org.argeo.eclipse.ui.dialogs.ErrorFeedback; import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.MaintainedRepository; import org.argeo.jcr.RepositoryRegister; import org.argeo.jcr.UserJcrUtils; import org.argeo.util.security.Keyring; @@ -55,9 +54,8 @@ public class RepositoriesElem extends TreeParent implements ArgeoNames { private final Session userSession; private final Keyring keyring; - public RepositoriesElem(String name, RepositoryRegister repositoryRegister, - RepositoryFactory repositoryFactory, TreeParent parent, - Session userSession, Keyring keyring) { + public RepositoriesElem(String name, RepositoryRegister repositoryRegister, RepositoryFactory repositoryFactory, + TreeParent parent, Session userSession, Keyring keyring) { super(name); this.repositoryRegister = repositoryRegister; this.repositoryFactory = repositoryFactory; @@ -75,15 +73,14 @@ public class RepositoriesElem extends TreeParent implements ArgeoNames { return super.getChildren(); } else { // initialize current object - Map refRepos = repositoryRegister - .getRepositories(); + Map refRepos = repositoryRegister.getRepositories(); for (String name : refRepos.keySet()) { Repository repository = refRepos.get(name); - if (repository instanceof MaintainedRepository) - super.addChild(new MaintainedRepositoryElem(name, - repository, this)); - else - super.addChild(new RepositoryElem(name, repository, this)); + // if (repository instanceof MaintainedRepository) + // super.addChild(new MaintainedRepositoryElem(name, + // repository, this)); + // else + super.addChild(new RepositoryElem(name, repository, this)); } // remote @@ -91,16 +88,14 @@ public class RepositoriesElem extends TreeParent implements ArgeoNames { try { addRemoteRepositories(keyring); } catch (RepositoryException e) { - throw new ArgeoException( - "Cannot browse remote repositories", e); + throw new ArgeoException("Cannot browse remote repositories", e); } } return super.getChildren(); } } - protected void addRemoteRepositories(Keyring jcrKeyring) - throws RepositoryException { + protected void addRemoteRepositories(Keyring jcrKeyring) throws RepositoryException { Node userHome = UserJcrUtils.getUserHome(userSession); if (userHome != null && userHome.hasNode(ARGEO_REMOTE)) { NodeIterator it = userHome.getNode(ARGEO_REMOTE).getNodes(); @@ -108,13 +103,11 @@ public class RepositoriesElem extends TreeParent implements ArgeoNames { Node remoteNode = it.nextNode(); String uri = remoteNode.getProperty(ARGEO_URI).getString(); try { - RemoteRepositoryElem remoteRepositoryNode = new RemoteRepositoryElem( - remoteNode.getName(), repositoryFactory, uri, this, - userSession, jcrKeyring, remoteNode.getPath()); + RemoteRepositoryElem remoteRepositoryNode = new RemoteRepositoryElem(remoteNode.getName(), + repositoryFactory, uri, this, userSession, jcrKeyring, remoteNode.getPath()); super.addChild(remoteRepositoryNode); } catch (Exception e) { - ErrorFeedback.show("Cannot add remote repository " - + remoteNode, e); + ErrorFeedback.show("Cannot add remote repository " + remoteNode, e); } } } diff --git a/org.argeo.server.jcr/ext/test/org/argeo/jcr/spring/CollectionsObject.java b/org.argeo.server.jcr/ext/test/org/argeo/jcr/spring/CollectionsObject.java deleted file mode 100644 index eadabfdad..000000000 --- a/org.argeo.server.jcr/ext/test/org/argeo/jcr/spring/CollectionsObject.java +++ /dev/null @@ -1,87 +0,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. - */ -package org.argeo.jcr.spring; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class CollectionsObject { - private String id; - private String label; - private SimpleObject simpleObject; - private List stringList = new ArrayList(); - private Map floatMap = new HashMap(); - private Map objectMap = new HashMap(); - private Map> mapOfMaps = new HashMap>(); - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public SimpleObject getSimpleObject() { - return simpleObject; - } - - public void setSimpleObject(SimpleObject simpleObject) { - this.simpleObject = simpleObject; - } - - public List getStringList() { - return stringList; - } - - public void setStringList(List stringList) { - this.stringList = stringList; - } - - public Map getFloatMap() { - return floatMap; - } - - public void setFloatMap(Map floatMap) { - this.floatMap = floatMap; - } - - public Map getObjectMap() { - return objectMap; - } - - public void setObjectMap(Map objectMap) { - this.objectMap = objectMap; - } - - public Map> getMapOfMaps() { - return mapOfMaps; - } - - public void setMapOfMaps(Map> mapOfMaps) { - this.mapOfMaps = mapOfMaps; - } -} diff --git a/org.argeo.server.jcr/ext/test/org/argeo/jcr/spring/MapperTest.java b/org.argeo.server.jcr/ext/test/org/argeo/jcr/spring/MapperTest.java deleted file mode 100644 index e4bccd9ff..000000000 --- a/org.argeo.server.jcr/ext/test/org/argeo/jcr/spring/MapperTest.java +++ /dev/null @@ -1,47 +0,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. - */ -package org.argeo.jcr.spring; - -import javax.jcr.Node; - -import org.argeo.jackrabbit.unit.AbstractJackrabbitTestCase; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.spring.BeanNodeMapper; - -@Deprecated -public class MapperTest extends AbstractJackrabbitTestCase { - public void testSimpleObject() throws Exception { - SimpleObject mySo = new SimpleObject(); - mySo.setInteger(100); - mySo.setString("hello world"); - - OtherObject oo1 = new OtherObject(); - oo1.setKey("someKey"); - oo1.setValue("stringValue"); - mySo.setOtherObject(oo1); - - OtherObject oo2 = new OtherObject(); - oo2.setKey("anotherSimpleObject"); - oo2.setValue(new SimpleObject()); - mySo.setAnotherObject(oo2); - - BeanNodeMapper bnm = new BeanNodeMapper(); - - Node node = bnm.save(session(), mySo); - session().save(); - JcrUtils.debug(node); - } -} diff --git a/org.argeo.server.jcr/ext/test/org/argeo/jcr/spring/OtherObject.java b/org.argeo.server.jcr/ext/test/org/argeo/jcr/spring/OtherObject.java deleted file mode 100644 index d6fb699b2..000000000 --- a/org.argeo.server.jcr/ext/test/org/argeo/jcr/spring/OtherObject.java +++ /dev/null @@ -1,37 +0,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. - */ -package org.argeo.jcr.spring; - -public class OtherObject { - private String key; - private Object value; - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public Object getValue() { - return value; - } - - public void setValue(Object value) { - this.value = value; - } -} diff --git a/org.argeo.server.jcr/ext/test/org/argeo/jcr/spring/SimpleObject.java b/org.argeo.server.jcr/ext/test/org/argeo/jcr/spring/SimpleObject.java deleted file mode 100644 index d18dd04f6..000000000 --- a/org.argeo.server.jcr/ext/test/org/argeo/jcr/spring/SimpleObject.java +++ /dev/null @@ -1,77 +0,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. - */ -package org.argeo.jcr.spring; - -import java.util.UUID; - -public class SimpleObject { - private String string; - private String uuid = UUID.randomUUID().toString(); - private Integer integer; - private OtherObject otherObject; - private OtherObject anotherObject; - - public String getString() { - return string; - } - - public void setString(String sting) { - this.string = sting; - } - - public Integer getInteger() { - return integer; - } - - public void setInteger(Integer integer) { - this.integer = integer; - } - - public OtherObject getOtherObject() { - return otherObject; - } - - public void setOtherObject(OtherObject otherObject) { - this.otherObject = otherObject; - } - - public OtherObject getAnotherObject() { - return anotherObject; - } - - public void setAnotherObject(OtherObject anotherObject) { - this.anotherObject = anotherObject; - } - - @Override - public boolean equals(Object obj) { - return string.equals(((SimpleObject) obj).string); - } - - @Override - public int hashCode() { - return string.hashCode(); - } - - public void setUuid(String uuid) { - this.uuid = uuid; - } - - public String getUuid() { - return uuid; - } - -} diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitAuthorizations.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitAuthorizations.java deleted file mode 100644 index 84e07992f..000000000 --- a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitAuthorizations.java +++ /dev/null @@ -1,64 +0,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. - */ -package org.argeo.jackrabbit; - -import java.security.Principal; -import java.util.List; - -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.jcr.security.JcrAuthorizations; - -/** Apply authorizations to a Jackrabbit repository. */ -@Deprecated -public class JackrabbitAuthorizations extends JcrAuthorizations { - private final static Log log = LogFactory.getLog(JackrabbitAuthorizations.class); - - // private List groupPrefixes = Arrays.asList(new String[] { "ROLE_" - // });// new - // ArrayList(); - - @Override - protected Principal getOrCreatePrincipal(Session session, String principalName) throws RepositoryException { - String msg = "Use org.argeo.jcr.security.JcrAuthorizations instead of org.argeo.jackrabbit.JackrabbitAuthorizations"; - log.error(msg); - throw new UnsupportedOperationException(msg); - // UserManager um = ((JackrabbitSession) session).getUserManager(); - // synchronized (um) { - // Authorizable authorizable = um.getAuthorizable(principalName); - // if (authorizable == null) { - // groupPrefixes: for (String groupPrefix : groupPrefixes) { - // if (principalName.startsWith(groupPrefix)) { - // authorizable = um.createGroup(principalName); - // log.info("Created group " + principalName); - // break groupPrefixes; - // } - // } - // if (authorizable == null) - // throw new ArgeoException("Authorizable " + principalName - // + " not found"); - // } - // return authorizable.getPrincipal(); - // } - } - - public void setGroupPrefixes(List groupsToCreate) { - // this.groupPrefixes = groupsToCreate; - } -} diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitContainer.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitContainer.java index 85e9e203f..547db9b0d 100644 --- a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitContainer.java +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitContainer.java @@ -41,7 +41,6 @@ import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; import org.argeo.ArgeoException; import org.argeo.jcr.ArgeoNames; import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.MaintainedRepository; import org.springframework.core.io.Resource; import org.springframework.util.SystemPropertyUtils; import org.xml.sax.InputSource; @@ -50,8 +49,8 @@ import org.xml.sax.InputSource; * Wrapper around a Jackrabbit repository which allows to configure it in Spring * and expose it as a {@link Repository}. */ -public class JackrabbitContainer extends JackrabbitWrapper implements - MaintainedRepository { +@Deprecated +public class JackrabbitContainer extends JackrabbitWrapper { private final static Log log = LogFactory.getLog(JackrabbitContainer.class); // local @@ -81,8 +80,7 @@ public class JackrabbitContainer extends JackrabbitWrapper implements // long begin = System.currentTimeMillis(); if (getRepository() != null) - throw new ArgeoException( - "Cannot be used to wrap another repository"); + throw new ArgeoException("Cannot be used to wrap another repository"); Repository repository = createJackrabbitRepository(); super.setRepository(repository); @@ -108,14 +106,12 @@ public class JackrabbitContainer extends JackrabbitWrapper implements // temporary if (inMemory && getHomeDirectory().exists()) { FileUtils.deleteDirectory(getHomeDirectory()); - log.warn("Deleted Jackrabbit home directory " - + getHomeDirectory()); + log.warn("Deleted Jackrabbit home directory " + getHomeDirectory()); } // process configuration file Properties vars = getConfigurationProperties(); - vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, - getHomeDirectory().getCanonicalPath()); + vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, getHomeDirectory().getCanonicalPath()); InputSource is; if (configurationXml != null) is = configurationXml; @@ -132,13 +128,11 @@ public class JackrabbitContainer extends JackrabbitWrapper implements double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; if (log.isTraceEnabled()) - log.trace("Created Jackrabbit repository in " + duration - + " s, home: " + getHomeDirectory()); + log.trace("Created Jackrabbit repository in " + duration + " s, home: " + getHomeDirectory()); return repository; } catch (Exception e) { - throw new ArgeoException("Cannot create Jackrabbit repository " - + getHomeDirectory(), e); + throw new ArgeoException("Cannot create Jackrabbit repository " + getHomeDirectory(), e); } finally { IOUtils.closeQuietly(configurationIn); } @@ -149,12 +143,8 @@ public class JackrabbitContainer extends JackrabbitWrapper implements try { if (homeDirectory == null) { if (inMemory) { - homeDirectory = new File( - System.getProperty("java.io.tmpdir") - + File.separator - + System.getProperty("user.name") - + File.separator + "jackrabbit-" - + UUID.randomUUID()); + homeDirectory = new File(System.getProperty("java.io.tmpdir") + File.separator + + System.getProperty("user.name") + File.separator + "jackrabbit-" + UUID.randomUUID()); homeDirectory.mkdirs(); // will it work if directory is not empty?? homeDirectory.deleteOnExit(); @@ -163,8 +153,7 @@ public class JackrabbitContainer extends JackrabbitWrapper implements return homeDirectory.getCanonicalFile(); } catch (IOException e) { - throw new ArgeoException("Cannot get canonical file for " - + homeDirectory, e); + throw new ArgeoException("Cannot get canonical file for " + homeDirectory, e); } } @@ -198,9 +187,7 @@ public class JackrabbitContainer extends JackrabbitWrapper implements if (restartAndClearCaches) { Repository repository = getRepository(); if (repository instanceof RepositoryImpl) { - JackrabbitDataModelMigration - .clearRepositoryCaches(((RepositoryImpl) repository) - .getConfig()); + JackrabbitDataModelMigration.clearRepositoryCaches(((RepositoryImpl) repository).getConfig()); } ((JackrabbitRepository) repository).shutdown(); createJackrabbitRepository(); @@ -216,12 +203,9 @@ public class JackrabbitContainer extends JackrabbitWrapper implements for (JackrabbitDataModelMigration dataModelMigration : new TreeSet( dataModelMigrations)) { try { - if (session.itemExists(dataModelMigration - .getDataModelNodePath())) { - Node dataModelNode = session.getNode(dataModelMigration - .getDataModelNodePath()); - dataModelNode.setProperty( - ArgeoNames.ARGEO_DATA_MODEL_VERSION, + if (session.itemExists(dataModelMigration.getDataModelNodePath())) { + Node dataModelNode = session.getNode(dataModelMigration.getDataModelNodePath()); + dataModelNode.setProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION, dataModelMigration.getTargetVersion()); session.save(); } @@ -243,20 +227,17 @@ public class JackrabbitContainer extends JackrabbitWrapper implements if (getHomeDirectory().exists()) { FileUtils.deleteDirectory(getHomeDirectory()); if (log.isDebugEnabled()) - log.debug("Deleted Jackrabbit home directory " - + getHomeDirectory()); + log.debug("Deleted Jackrabbit home directory " + getHomeDirectory()); } double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; if (log.isTraceEnabled()) - log.trace("Destroyed Jackrabbit repository in " + duration - + " s, home: " + getHomeDirectory()); + log.trace("Destroyed Jackrabbit repository in " + duration + " s, home: " + getHomeDirectory()); } repository = null; } public void dispose() { - throw new IllegalArgumentException( - "Call destroy() method instead of dispose()"); + throw new IllegalArgumentException("Call destroy() method instead of dispose()"); } /* @@ -267,11 +248,9 @@ public class JackrabbitContainer extends JackrabbitWrapper implements */ protected InputStream readConfiguration() { try { - return configuration != null ? configuration.getInputStream() - : null; + return configuration != null ? configuration.getInputStream() : null; } catch (IOException e) { - throw new ArgeoException("Cannot read Jackrabbit configuration " - + configuration, e); + throw new ArgeoException("Cannot read Jackrabbit configuration " + configuration, e); } } @@ -285,8 +264,7 @@ public class JackrabbitContainer extends JackrabbitWrapper implements try { return variables != null ? variables.getInputStream() : null; } catch (IOException e) { - throw new ArgeoException("Cannot read Jackrabbit variables " - + variables, e); + throw new ArgeoException("Cannot read Jackrabbit variables " + variables, e); } } @@ -294,8 +272,7 @@ public class JackrabbitContainer extends JackrabbitWrapper implements * Resolves ${} placeholders in the provided string. Based on system * properties if no map is provided. */ - protected String resolvePlaceholders(String string, - Map variables) { + protected String resolvePlaceholders(String string, Map variables) { return SystemPropertyUtils.resolvePlaceholders(string); } @@ -315,8 +292,7 @@ public class JackrabbitContainer extends JackrabbitWrapper implements // resolve system properties for (Object key : vars.keySet()) { // TODO: implement a smarter mechanism to resolve nested ${} - String newValue = resolvePlaceholders( - vars.getProperty(key.toString()), null); + String newValue = resolvePlaceholders(vars.getProperty(key.toString()), null); vars.put(key, newValue); } // override with system properties @@ -352,8 +328,7 @@ public class JackrabbitContainer extends JackrabbitWrapper implements throw new ArgeoException("Cannot be used to wrap another repository"); } - public void setDataModelMigrations( - Set dataModelMigrations) { + public void setDataModelMigrations(Set dataModelMigrations) { this.dataModelMigrations = dataModelMigrations; } diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitDataModel.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitDataModel.java deleted file mode 100644 index b342d18bd..000000000 --- a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitDataModel.java +++ /dev/null @@ -1,283 +0,0 @@ -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 cndFiles = new ArrayList(); - /** - * 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 namespaces = new HashMap(); - - 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 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 deleted file mode 100644 index 5d78514b5..000000000 --- a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitNodeType.java +++ /dev/null @@ -1,6 +0,0 @@ -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/JackrabbitRepositoryFactory.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java index e5bb3bce0..3502abd59 100644 --- a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java @@ -48,12 +48,11 @@ import org.xml.sax.InputSource; * Jackrabbit repositories */ public class JackrabbitRepositoryFactory implements RepositoryFactory, ArgeoJcrConstants { - private final static Log log = LogFactory.getLog(JackrabbitRepositoryFactory.class); private Resource fileRepositoryConfiguration = new ClassPathResource("/org/argeo/jackrabbit/repository-h2.xml"); - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({ "rawtypes" }) public Repository getRepository(Map parameters) throws RepositoryException { // // check if can be found by alias // Repository repository = super.getRepository(parameters); @@ -73,13 +72,10 @@ public class JackrabbitRepositoryFactory implements RepositoryFactory, ArgeoJcrC repository = createRemoteRepository(uri); else if (uri.startsWith("file"))// http, https repository = createFileRepository(uri, parameters); - else if (uri.startsWith("vm")) { - log.warn("URI " - + uri - + " should have been managed by generic JCR repository factory"); - repository = getRepositoryByAlias(getAliasFromURI(uri)); - } - else + else if (uri.startsWith("vm")) { + log.warn("URI " + uri + " should have been managed by generic JCR repository factory"); + repository = getRepositoryByAlias(getAliasFromURI(uri)); + } else throw new ArgeoJcrException("Unrecognized URI format " + uri); } diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitWrapper.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitWrapper.java index 7288cdf4b..89a39496d 100644 --- a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitWrapper.java +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitWrapper.java @@ -61,7 +61,7 @@ import org.springframework.core.io.ResourceLoader; * Wrapper around a Jackrabbit repository which allows to simplify configuration * and intercept some actions. It exposes itself as a {@link Repository}. */ -@SuppressWarnings("deprecation") +@Deprecated public class JackrabbitWrapper extends JcrRepositoryWrapper implements JackrabbitRepository, ResourceLoaderAware { private final static Log log = LogFactory.getLog(JackrabbitWrapper.class); diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java deleted file mode 100644 index a617ec6e3..000000000 --- a/org.argeo.server.jcr/src/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java +++ /dev/null @@ -1,66 +0,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. - */ -package org.argeo.jackrabbit; - -import java.util.Collection; -import java.util.Hashtable; -import java.util.Properties; - -import javax.jcr.Repository; - -import org.argeo.jcr.ArgeoJcrException; -import org.osgi.framework.BundleContext; -import org.osgi.framework.InvalidSyntaxException; -import org.osgi.framework.ServiceReference; - -/** - * OSGi-aware Jackrabbit repository factory which can retrieve/publish - * {@link Repository} as OSGi services. - */ -public class OsgiJackrabbitRepositoryFactory extends JackrabbitRepositoryFactory { - private BundleContext bundleContext; - - @Override - protected Repository getRepositoryByAlias(String alias) { - try { - Collection> srs = bundleContext.getServiceReferences(Repository.class, - "(" + JCR_REPOSITORY_ALIAS + "=" + alias + ")"); - if (srs.size() == 0) - throw new ArgeoJcrException("No repository with alias " + alias + " found in OSGi registry"); - else if (srs.size() > 1) - throw new ArgeoJcrException( - srs.size() + " repositories with alias " + alias + " found in OSGi registry"); - return bundleContext.getService(srs.iterator().next()); - } catch (InvalidSyntaxException e) { - throw new ArgeoJcrException("Cannot find repository with alias " + alias, e); - } - } - - protected void publish(String alias, Repository repository, Properties properties) { - if (bundleContext != null) { - // do not modify reference - Hashtable props = new Hashtable(); - props.putAll(props); - props.put(JCR_REPOSITORY_ALIAS, alias); - bundleContext.registerService(Repository.class.getName(), repository, props); - } - } - - public void setBundleContext(BundleContext bundleContext) { - this.bundleContext = bundleContext; - } - -} diff --git a/org.argeo.server.jcr/src/org/argeo/jcr/MaintainedRepository.java b/org.argeo.server.jcr/src/org/argeo/jcr/MaintainedRepository.java deleted file mode 100644 index 702d47a5c..000000000 --- a/org.argeo.server.jcr/src/org/argeo/jcr/MaintainedRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.argeo.jcr; - -import javax.jcr.Repository; - -/** Abstracts maintenance operations on a {@link Repository} */ -public interface MaintainedRepository extends Repository { - -} diff --git a/org.argeo.server.jcr/src/org/argeo/jcr/NodeMapper.java b/org.argeo.server.jcr/src/org/argeo/jcr/NodeMapper.java deleted file mode 100644 index af792c3ca..000000000 --- a/org.argeo.server.jcr/src/org/argeo/jcr/NodeMapper.java +++ /dev/null @@ -1,29 +0,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. - */ -package org.argeo.jcr; - -import javax.jcr.Node; -import javax.jcr.Session; - -public interface NodeMapper { - public Object load(Node node); - - public void update(Node node, Object obj); - - public Node save(Session session, String path, Object obj); - - public void setNodeMapperProvider(NodeMapperProvider nmp); -} diff --git a/org.argeo.server.jcr/src/org/argeo/jcr/NodeMapperProvider.java b/org.argeo.server.jcr/src/org/argeo/jcr/NodeMapperProvider.java deleted file mode 100644 index 07e623bfd..000000000 --- a/org.argeo.server.jcr/src/org/argeo/jcr/NodeMapperProvider.java +++ /dev/null @@ -1,28 +0,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. - */ -package org.argeo.jcr; - -import javax.jcr.Node; - -/** Provides a node mapper relevant for this node. */ -public interface NodeMapperProvider { - - /** - * Node Mapper is chosen regarding the Jcr path of the node parameter - * @param Node node - * @return the node mapper or null if no relevant node mapper can be found. */ - public NodeMapper findNodeMapper(Node node); -} diff --git a/org.argeo.server.jcr/src/org/argeo/jcr/ThreadBoundJcrSessionFactory.java b/org.argeo.server.jcr/src/org/argeo/jcr/ThreadBoundJcrSessionFactory.java index 722215701..56caab0a3 100644 --- a/org.argeo.server.jcr/src/org/argeo/jcr/ThreadBoundJcrSessionFactory.java +++ b/org.argeo.server.jcr/src/org/argeo/jcr/ThreadBoundJcrSessionFactory.java @@ -126,6 +126,7 @@ public abstract class ThreadBoundJcrSessionFactory { } public void init() throws Exception { + log.error("SHOULD NOT BE USED ANYMORE"); monitoringThread = new MonitoringThread(); monitoringThread.start(); } diff --git a/org.argeo.server.jcr/src/org/argeo/jcr/spring/BeanNodeMapper.java b/org.argeo.server.jcr/src/org/argeo/jcr/spring/BeanNodeMapper.java deleted file mode 100644 index e78cee452..000000000 --- a/org.argeo.server.jcr/src/org/argeo/jcr/spring/BeanNodeMapper.java +++ /dev/null @@ -1,650 +0,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. - */ -package org.argeo.jcr.spring; - -import java.beans.PropertyDescriptor; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; - -import javax.jcr.Binary; -import javax.jcr.ItemNotFoundException; -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Property; -import javax.jcr.PropertyIterator; -import javax.jcr.PropertyType; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.Value; -import javax.jcr.ValueFactory; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.NodeMapper; -import org.argeo.jcr.NodeMapperProvider; -import org.springframework.beans.BeanWrapper; -import org.springframework.beans.BeanWrapperImpl; - -@Deprecated -public class BeanNodeMapper implements NodeMapper { - private final static Log log = LogFactory.getLog(BeanNodeMapper.class); - - private final static String NODE_VALUE = "value"; - - // private String keyNode = "bean:key"; - private String uuidProperty = "uuid"; - private String classProperty = "class"; - - private Boolean versioning = false; - private Boolean strictUuidReference = false; - - // TODO define a primaryNodeType Strategy - private String primaryNodeType = null; - - private ClassLoader classLoader = getClass().getClassLoader(); - - private NodeMapperProvider nodeMapperProvider; - - /** - * exposed method to retrieve a bean from a node - */ - public Object load(Node node) { - try { - if (nodeMapperProvider != null) { - NodeMapper nodeMapper = nodeMapperProvider.findNodeMapper(node); - if (nodeMapper != this) { - return nodeMapper.load(node); - } - } - return nodeToBean(node); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot load object from node " + node, e); - } - } - - /** Update an existing node with an object */ - public void update(Node node, Object obj) { - try { - if (nodeMapperProvider != null) { - - NodeMapper nodeMapper = nodeMapperProvider.findNodeMapper(node); - if (nodeMapper != this) { - nodeMapper.update(node, obj); - } else - beanToNode(createBeanWrapper(obj), node); - } else - beanToNode(createBeanWrapper(obj), node); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot update node " + node + " with " - + obj, e); - } - } - - /** - * if no storage path is given; we use canonical path - * - * @see this.storagePath() - */ - public Node save(Session session, Object obj) { - return save(session, storagePath(obj), obj); - } - - /** - * Create a new node to store an object. If the parentNode doesn't exist, it - * is created - * - * the primaryNodeType may be initialized before - */ - public Node save(Session session, String path, Object obj) { - try { - final Node node; - String parentPath = JcrUtils.parentPath(path); - // find or create parent node - Node parentNode; - if (session.itemExists(path)) - parentNode = (Node) session.getItem(parentPath); - else { - parentNode = JcrUtils.mkdirs(session, parentPath, null, null, - versioning); - } - // create node - - if (primaryNodeType != null) - node = parentNode.addNode(JcrUtils.lastPathElement(path), - primaryNodeType); - else - node = parentNode.addNode(JcrUtils.lastPathElement(path)); - - // Check specific cases - if (nodeMapperProvider != null) { - NodeMapper nodeMapper = nodeMapperProvider.findNodeMapper(node); - if (nodeMapper != this) { - nodeMapper.update(node, obj); - return node; - } - } - update(node, obj); - return node; - } catch (ArgeoException e) { - throw e; - } catch (Exception e) { - throw new ArgeoException("Cannot save or update " + obj + " under " - + path, e); - } - } - - /** - * Parse the FQN of a class to string with '/' delimiters Prefix the - * returned string with "/objects/" - */ - public String storagePath(Object obj) { - String clss = obj.getClass().getName(); - StringBuffer buf = new StringBuffer("/objects/"); - StringTokenizer st = new StringTokenizer(clss, "."); - while (st.hasMoreTokens()) { - buf.append(st.nextToken()).append('/'); - } - buf.append(obj.toString()); - return buf.toString(); - } - - @SuppressWarnings("unchecked") - /** - * Transforms a node into an object of the class defined by classProperty Property - */ - protected Object nodeToBean(Node node) throws RepositoryException { - if (log.isTraceEnabled()) - log.trace("Load " + node); - - try { - String clssName = node.getProperty(classProperty).getValue() - .getString(); - - BeanWrapper beanWrapper = createBeanWrapper(loadClass(clssName)); - - // process properties - PropertyIterator propIt = node.getProperties(); - props: while (propIt.hasNext()) { - Property prop = propIt.nextProperty(); - if (!beanWrapper.isWritableProperty(prop.getName())) - continue props; - - PropertyDescriptor pd = beanWrapper.getPropertyDescriptor(prop - .getName()); - Class propClass = pd.getPropertyType(); - - if (log.isTraceEnabled()) - log.trace("Load " + prop + ", propClass=" + propClass - + ", property descriptor=" + pd); - - // primitive list - if (propClass != null && List.class.isAssignableFrom(propClass)) { - List lst = new ArrayList(); - Class valuesClass = classFromProperty(prop); - if (valuesClass != null) - for (Value value : prop.getValues()) { - lst.add(asObject(value, valuesClass)); - } - continue props; - } - - // Case of other type of property accepted by jcr - // Long, Double, String, Binary, Date, Boolean, Name - Object value = asObject(prop.getValue(), pd.getPropertyType()); - if (value != null) - beanWrapper.setPropertyValue(prop.getName(), value); - } - - // process children nodes - NodeIterator nodeIt = node.getNodes(); - nodes: while (nodeIt.hasNext()) { - Node childNode = nodeIt.nextNode(); - String name = childNode.getName(); - if (!beanWrapper.isWritableProperty(name)) - continue nodes; - - PropertyDescriptor pd = beanWrapper.getPropertyDescriptor(name); - Class propClass = pd.getPropertyType(); - - // objects list - if (propClass != null && List.class.isAssignableFrom(propClass)) { - String lstClass = childNode.getProperty(classProperty) - .getString(); - List lst; - try { - lst = (List) loadClass(lstClass).newInstance(); - } catch (Exception e) { - lst = new ArrayList(); - } - - if (childNode.hasNodes()) { - // Look for children nodes - NodeIterator valuesIt = childNode.getNodes(); - while (valuesIt.hasNext()) { - Node lstValueNode = valuesIt.nextNode(); - Object lstValue = nodeToBean(lstValueNode); - lst.add(lstValue); - } - } else { - // look for a property with the same name which will - // provide - // primitives - Property childProp = childNode.getProperty(childNode - .getName()); - Class valuesClass = classFromProperty(childProp); - if (valuesClass != null) - if (childProp.getDefinition().isMultiple()) - for (Value value : childProp.getValues()) { - lst.add(asObject(value, valuesClass)); - } - else - lst.add(asObject(childProp.getValue(), - valuesClass)); - } - beanWrapper.setPropertyValue(name, lst); - continue nodes; - } - - // objects map - if (propClass != null && Map.class.isAssignableFrom(propClass)) { - String mapClass = childNode.getProperty(classProperty) - .getString(); - Map map; - try { - map = (Map) loadClass(mapClass) - .newInstance(); - } catch (Exception e) { - map = new HashMap(); - } - - // properties - PropertyIterator keysPropIt = childNode.getProperties(); - keyProps: while (keysPropIt.hasNext()) { - Property keyProp = keysPropIt.nextProperty(); - // FIXME: use property editor - String key = keyProp.getName(); - if (classProperty.equals(key)) - continue keyProps; - - Class keyPropClass = classFromProperty(keyProp); - if (keyPropClass != null) { - Object mapValue = asObject(keyProp.getValue(), - keyPropClass); - map.put(key, mapValue); - } - } - - // node - NodeIterator keysIt = childNode.getNodes(); - while (keysIt.hasNext()) { - Node mapValueNode = keysIt.nextNode(); - // FIXME: use property editor - Object key = mapValueNode.getName(); - - Object mapValue = nodeToBean(mapValueNode); - - map.put(key, mapValue); - } - beanWrapper.setPropertyValue(name, map); - continue nodes; - } - - // default - Object value = nodeToBean(childNode); - beanWrapper.setPropertyValue(name, value); - - } - return beanWrapper.getWrappedInstance(); - } catch (Exception e) { - throw new ArgeoException("Cannot map node " + node, e); - } - } - - /** - * Transforms an object to the specified jcr Node in order to persist it. - * - * @param beanWrapper - * @param node - * @throws RepositoryException - */ - protected void beanToNode(BeanWrapper beanWrapper, Node node) - throws RepositoryException { - properties: for (PropertyDescriptor pd : beanWrapper - .getPropertyDescriptors()) { - String name = pd.getName(); - if (!beanWrapper.isReadableProperty(name)) - continue properties;// skip - - Object value = beanWrapper.getPropertyValue(name); - if (value == null) { - // remove values when updating - if (node.hasProperty(name)) - node.setProperty(name, (Value) null); - if (node.hasNode(name)) - node.getNode(name).remove(); - - continue properties; - } - - // if (uuidProperty != null && uuidProperty.equals(name)) { - // // node.addMixin(ArgeoJcrConstants.MIX_REFERENCEABLE); - // node.setProperty(ArgeoJcrConstants.JCR_UUID, value.toString()); - // continue properties; - // } - - if ("class".equals(name)) { - if (classProperty != null) { - node.setProperty(classProperty, - ((Class) value).getName()); - // TODO: store a class hierarchy? - } - continue properties; - } - - // Some bean reference other classes. We must deal with this case - if (value instanceof Class) { - node.setProperty(name, ((Class) value).getName()); - continue properties; - } - - Value val = asValue(node.getSession(), value); - if (val != null) { - node.setProperty(name, val); - continue properties; - } - - if (value instanceof List) { - List lst = (List) value; - addList(node, name, lst); - continue properties; - } - - if (value instanceof Map) { - Map map = (Map) value; - addMap(node, name, map); - continue properties; - } - - BeanWrapper child = createBeanWrapper(value); - // TODO: delegate to another mapper - - // TODO: deal with references - // Node childNode = findChildReference(session, child); - // if (childNode != null) { - // node.setProperty(name, childNode); - // continue properties; - // } - - // default case (recursive) - if (node.hasNode(name)) {// update - // TODO: optimize - node.getNode(name).remove(); - } - Node childNode = node.addNode(name); - beanToNode(child, childNode); - } - } - - /** - * Process specific case of list - * - * @param node - * @param name - * @param lst - * @throws RepositoryException - */ - protected void addList(Node node, String name, List lst) - throws RepositoryException { - if (node.hasNode(name)) {// update - // TODO: optimize - node.getNode(name).remove(); - } - - Node listNode = node.addNode(name); - listNode.setProperty(classProperty, lst.getClass().getName()); - Value[] values = new Value[lst.size()]; - boolean atLeastOneSet = false; - for (int i = 0; i < lst.size(); i++) { - Object lstValue = lst.get(i); - values[i] = asValue(node.getSession(), lstValue); - if (values[i] != null) { - atLeastOneSet = true; - } else { - Node childNode = findChildReference(node.getSession(), - createBeanWrapper(lstValue)); - if (childNode != null) { - values[i] = node.getSession().getValueFactory() - .createValue(childNode); - atLeastOneSet = true; - } - } - } - - // will be either properties or nodes, not both - if (!atLeastOneSet && lst.size() != 0) { - for (Object lstValue : lst) { - Node childNode = listNode.addNode(NODE_VALUE); - beanToNode(createBeanWrapper(lstValue), childNode); - } - } else { - listNode.setProperty(name, values); - } - } - - /** - * Process specific case of maps. - * - * @param node - * @param name - * @param map - * @throws RepositoryException - */ - protected void addMap(Node node, String name, Map map) - throws RepositoryException { - if (node.hasNode(name)) {// update - // TODO: optimize - node.getNode(name).remove(); - } - - Node mapNode = node.addNode(name); - mapNode.setProperty(classProperty, map.getClass().getName()); - for (Object key : map.keySet()) { - Object mapValue = map.get(key); - // PropertyEditor pe = beanWrapper.findCustomEditor(key.getClass(), - // null); - String keyStr; - // if (pe == null) { - if (key instanceof CharSequence) - keyStr = key.toString(); - else - throw new ArgeoException( - "Cannot find property editor for class " - + key.getClass()); - // } else { - // pe.setValue(key); - // keyStr = pe.getAsText(); - // } - // TODO: check string format - - Value mapVal = asValue(node.getSession(), mapValue); - if (mapVal != null) - mapNode.setProperty(keyStr, mapVal); - else { - Node entryNode = mapNode.addNode(keyStr); - beanToNode(createBeanWrapper(mapValue), entryNode); - } - - } - - } - - protected BeanWrapper createBeanWrapper(Object obj) { - return new BeanWrapperImpl(obj); - } - - protected BeanWrapper createBeanWrapper(Class clss) { - return new BeanWrapperImpl(clss); - } - - /** Returns null if value cannot be found */ - protected Value asValue(Session session, Object value) - throws RepositoryException { - ValueFactory valueFactory = session.getValueFactory(); - if (value instanceof Integer) - return valueFactory.createValue((Integer) value); - else if (value instanceof Long) - return valueFactory.createValue((Long) value); - else if (value instanceof Float) - return valueFactory.createValue((Float) value); - else if (value instanceof Double) - return valueFactory.createValue((Double) value); - else if (value instanceof Boolean) - return valueFactory.createValue((Boolean) value); - else if (value instanceof Calendar) - return valueFactory.createValue((Calendar) value); - else if (value instanceof Date) { - Calendar cal = new GregorianCalendar(); - cal.setTime((Date) value); - return valueFactory.createValue(cal); - } else if (value instanceof CharSequence) - return valueFactory.createValue(value.toString()); - else if (value instanceof InputStream) { - Binary binary = session.getValueFactory().createBinary( - (InputStream) value); - return valueFactory.createValue(binary); - } else - return null; - } - - protected Class classFromProperty(Property property) - throws RepositoryException { - switch (property.getType()) { - case PropertyType.LONG: - return Long.class; - case PropertyType.DOUBLE: - return Double.class; - case PropertyType.STRING: - return String.class; - case PropertyType.BOOLEAN: - return Boolean.class; - case PropertyType.DATE: - return Calendar.class; - case PropertyType.NAME: - return null; - default: - throw new ArgeoException("Cannot find class for property " - + property + ", type=" - + PropertyType.nameFromValue(property.getType())); - } - } - - protected Object asObject(Value value, Class propClass) - throws RepositoryException { - if (propClass.equals(Integer.class)) - return (int) value.getLong(); - else if (propClass.equals(Long.class)) - return value.getLong(); - else if (propClass.equals(Float.class)) - return (float) value.getDouble(); - else if (propClass.equals(Double.class)) - return value.getDouble(); - else if (propClass.equals(Boolean.class)) - return value.getBoolean(); - else if (CharSequence.class.isAssignableFrom(propClass)) - return value.getString(); - else if (InputStream.class.isAssignableFrom(propClass)) - return value.getBinary().getStream(); - else if (Calendar.class.isAssignableFrom(propClass)) - return value.getDate(); - else if (Date.class.isAssignableFrom(propClass)) - return value.getDate().getTime(); - else - return null; - } - - protected Node findChildReference(Session session, BeanWrapper child) - throws RepositoryException { - if (child.isReadableProperty(uuidProperty)) { - String childUuid = child.getPropertyValue(uuidProperty).toString(); - try { - return session.getNodeByIdentifier(childUuid); - } catch (ItemNotFoundException e) { - if (strictUuidReference) - throw new ArgeoException("No node found with uuid " - + childUuid, e); - } - } - return null; - } - - protected Class loadClass(String name) { - // log.debug("Class loader: " + classLoader); - try { - return classLoader.loadClass(name); - } catch (ClassNotFoundException e) { - throw new ArgeoException("Cannot load class " + name, e); - } - } - - protected String propertyName(String name) { - return name; - } - - public void setVersioning(Boolean versioning) { - this.versioning = versioning; - } - - public void setUuidProperty(String uuidProperty) { - this.uuidProperty = uuidProperty; - } - - public void setClassProperty(String classProperty) { - this.classProperty = classProperty; - } - - public void setStrictUuidReference(Boolean strictUuidReference) { - this.strictUuidReference = strictUuidReference; - } - - public void setPrimaryNodeType(String primaryNodeType) { - this.primaryNodeType = primaryNodeType; - } - - public void setClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - public void setNodeMapperProvider(NodeMapperProvider nodeMapperProvider) { - this.nodeMapperProvider = nodeMapperProvider; - } - - public String getPrimaryNodeType() { - return this.primaryNodeType; - } - - public String getClassProperty() { - return this.classProperty; - } -}