Load JCR CND files with OSGi bundle context
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 4 Nov 2011 19:47:30 +0000 (19:47 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 4 Nov 2011 19:47:30 +0000 (19:47 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@4879 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

13 files changed:
eclipse/runtime/org.argeo.eclipse.ui/pom.xml
eclipse/runtime/org.argeo.eclipse.ui/src/main/java/org/argeo/eclipse/spring/ApplicationContextTracker.java
eclipse/runtime/org.argeo.eclipse.ui/src/main/java/org/argeo/eclipse/ui/ArgeoUiPlugin.java
security/modules/org.argeo.security.dao.ldap/META-INF/spring/security-ldap-jcr.xml
security/modules/org.argeo.security.dao.os/META-INF/spring/security-os-osgi.xml
security/modules/org.argeo.security.dao.os/META-INF/spring/security-os.xml
security/modules/org.argeo.security.dao.os/pom.xml
security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java
server/modules/org.argeo.node.repofactory.jackrabbit/META-INF/spring/repofactory.xml
server/runtime/org.argeo.server.jackrabbit/pom.xml
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java
server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java
server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java

index d8c7f1435695fb37fdff79852dd040e19191bcba..cda0a6bebfbedd12bfb7e98d66eab83e20e72f86 100644 (file)
@@ -1,4 +1,5 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
                <groupId>org.argeo.commons.eclipse</groupId>
@@ -29,6 +30,7 @@
                                <version>${version.maven-bundle-plugin}</version>
                                <configuration>
                                        <instructions>
+                                               <Bundle-SymbolicName>${project.artifactID};singleton:=true</Bundle-SymbolicName>
                                                <Bundle-ActivationPolicy>lazy</Bundle-ActivationPolicy>
                                                <Bundle-Activator>org.argeo.eclipse.ui.ArgeoUiPlugin</Bundle-Activator>
                                                <Require-Bundle>org.eclipse.ui;resolution:=optional,org.eclipse.rap.ui;resolution:=optional,org.eclipse.core.runtime</Require-Bundle>
index 816edc1be864edc0173b187b342907c5e66208d3..7a5a71e39789e48328f9c515d8a77662b1c8add1 100644 (file)
@@ -115,8 +115,9 @@ class ApplicationContextTracker {
                if (contributorBundle.getState() != Bundle.ACTIVE\r
                                && contributorBundle.getState() != Bundle.STARTING) {\r
                        try {\r
-                               log.info("Starting bundle: "\r
-                                               + contributorBundle.getSymbolicName());\r
+                               if (log.isTraceEnabled())\r
+                                       log.trace("Starting bundle: "\r
+                                                       + contributorBundle.getSymbolicName());\r
                                contributorBundle.start();\r
                        } catch (BundleException e) {\r
                                e.printStackTrace();\r
index 73fef7812c5ef1fceb5849014a1494daf89eba5a..c0394fff1a7fce2e927c7cd3f334bf4f0de5ef20 100644 (file)
@@ -22,84 +22,45 @@ import org.eclipse.core.runtime.ILogListener;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 
 /**
  * The activator class controls the plug-in life cycle
  */
 public class ArgeoUiPlugin extends AbstractUIPlugin implements ILogListener {
-
-       // The plug-in ID
        public static final String PLUGIN_ID = "org.argeo.eclipse.ui";
-
-       private final static String SPRING_OSGI_EXTENDER = "org.springframework.osgi.extender";
-
        private final static Log log = LogFactory.getLog(ArgeoUiPlugin.class);
-
        // The shared instance
        private static ArgeoUiPlugin plugin;
 
-       private BundleContext bundleContext;
-
-       /**
-        * The constructor
-        */
-       public ArgeoUiPlugin() {
-       }
-
-       /*
-        * (non-Javadoc)
-        * 
-        * @see
-        * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext
-        * )
-        */
        public void start(BundleContext context) throws Exception {
                super.start(context);
-               plugin = this;
-               bundleContext = context;
-
-               Platform.addLogListener(this);
-               log.debug("Eclipse logging now directed to standard logging");
-
-               // Make sure that the Spring OSGi extender is started
-               Bundle osgiExtBundle = Platform.getBundle(SPRING_OSGI_EXTENDER);
-               if (osgiExtBundle != null)
-                       osgiExtBundle.start();
-               else
-                       log.error("Spring OSGi Extender not found");
-
+               // weirdly, the start method is called twice...
+               if (plugin == null) {
+                       plugin = this;
+                       Platform.addLogListener(this);
+                       log.debug("Eclipse logging now directed to standard logging");
+               }
        }
 
-       /*
-        * (non-Javadoc)
-        * 
-        * @see
-        * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
-        * )
-        */
        public void stop(BundleContext context) throws Exception {
-               Platform.removeLogListener(this);
-               log.debug("Eclipse logging not directed anymore to standard logging");
-
-               plugin = null;
-               super.stop(context);
+               try {
+                       // weirdly, the stop method is called twice...
+                       if (plugin != null) {
+                               Platform.removeLogListener(this);
+                               log.debug("Eclipse logging not directed anymore to standard logging");
+                               plugin = null;
+                       }
+               } finally {
+                       super.stop(context);
+               }
        }
 
-       /**
-        * Returns the shared instance
-        * 
-        * @return the shared instance
-        */
+       /** Returns the shared instance */
        public static ArgeoUiPlugin getDefault() {
                return plugin;
        }
 
-       public BundleContext getBundleContext() {
-               return bundleContext;
-       }
-
        public void logging(IStatus status, String plugin) {
                Log pluginLog = LogFactory.getLog(plugin);
                Integer severity = status.getSeverity();
index 376a8e914ec8bd1834a9aa560affb2872123ebba..ef18e04197b162d43a3a132f0ec93ab22009a1ae 100644 (file)
@@ -17,6 +17,7 @@
                        </list>
                </property>
                <property name="repository" ref="nodeRepository" />
+               <property name="bundleContext" ref="bundleContext" />
        </bean>
 
        <bean id="jcrLdapSynchronizer" class="org.argeo.security.ldap.jcr.JcrLdapSynchronizer"
index 4386b19c2b2b42c9c955d5fae30c52d9ccc2403b..493d80a8be1cb4e2b63e4fcd02e395347896d9ca 100644 (file)
@@ -14,9 +14,9 @@
                filter="(argeo.jcr.repository.alias=node)" />\r
 \r
        <!-- SERVICES -->\r
-       <service ref="systemExecutionService" interface="org.argeo.security.SystemExecutionService" />\r
-\r
        <service ref="authenticationManager"\r
                interface="org.springframework.security.AuthenticationManager" />\r
 \r
+       <service ref="systemExecutionService" interface="org.argeo.security.SystemExecutionService" />\r
+\r
 </beans:beans>
\ No newline at end of file
index b337218835643a34aa75d12abc1af4d0bdcfe9da..33b4be32fe18d3d4a63b58a6028169548363921e 100644 (file)
@@ -20,6 +20,7 @@
                        </list>
                </property>
                <property name="repository" ref="nodeRepository" />
+               <property name="bundleContext" ref="bundleContext" />
        </bean>
 
        <bean id="systemExecutionService" class="org.argeo.security.core.KeyBasedSystemExecutionService">
@@ -38,8 +39,8 @@
 
        <!-- Authentication providers -->
        <bean id="osJcrAuthenticationProvider" class="org.argeo.security.jcr.OsJcrAuthenticationProvider"
-               init-method="init" destroy-method="destroy">
-               <property name="repository" ref="argeoDataModel" />
+               init-method="init" destroy-method="destroy" depends-on="argeoDataModel">
+               <property name="repository" ref="nodeRepository" />
        </bean>
 
        <bean id="authByAdapterProvider"
index e19515a1fa7083c2db92150655900ca3cf515768..6964e0940f7486d0a895daea7a27eb9e47b5862d 100644 (file)
@@ -9,4 +9,20 @@
        </parent>
        <artifactId>org.argeo.security.dao.os</artifactId>
        <name>Commons Security DAO OS</name>
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.felix</groupId>
+                               <artifactId>maven-bundle-plugin</artifactId>
+                               <configuration>
+                                       <instructions>
+                                               <Import-Package>
+                                                       *,
+                                                       org.argeo.jcr,
+                                               </Import-Package>
+                                       </instructions>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
 </project>
\ No newline at end of file
index f898d9df3fceaebdcce46c085d07700f36aef61f..ce2511a57179c0a9737edb72f43c5ea5c2c71d0f 100644 (file)
@@ -78,12 +78,12 @@ public abstract class AbstractSecureApplication implements IApplication {
                                .getName();
                if (log.isDebugEnabled())
                        log.debug(username + " logged in");
-               display.disposeExec(new Runnable() {
-                       public void run() {
-                               log.debug("Display disposed");
-                               logout(loginContext, username);
-                       }
-               });
+//             display.disposeExec(new Runnable() {
+//                     public void run() {
+//                             log.debug("Display disposed");
+//                             logout(loginContext, username);
+//                     }
+//             });
 
                try {
                        PrivilegedAction<?> privilegedAction = new PrivilegedAction<Object>() {
index 73c9a9fc73e76a48cc9aceea1fb35f3b5f2f2d6b..266f2673fd54dceff8d8adaeb59a6574e6740e8c 100644 (file)
@@ -3,6 +3,8 @@
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 
-       <bean id="repositoryFactory" class="org.argeo.jackrabbit.JackrabbitRepositoryFactory" />
+       <bean id="repositoryFactory" class="org.argeo.jackrabbit.JackrabbitRepositoryFactory">
+               <property name="bundleContext" ref="bundleContext" />
+       </bean>
 
 </beans>
\ No newline at end of file
index dc02e48d92ea29bfc51d3107afa24be46b8a5927..62056ecf7b71e072b6b5dc6d671f6739bae4d4ef 100644 (file)
@@ -1,4 +1,5 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
                <groupId>org.argeo.commons.server</groupId>
                        <version>0.3.4-SNAPSHOT</version>
                </dependency>
 
+               <!-- OSGi -->
+               <dependency>
+                       <groupId>org.eclipse.osgi</groupId>
+                       <artifactId>org.eclipse.osgi</artifactId>
+                       <scope>provided</scope>
+               </dependency>
+
                <!-- Spring -->
                <dependency>
                        <groupId>org.springframework</groupId>
index 10c7af1d05e002359ce4abf758b3ebb7d9c08fa0..70bc300a1b247af9fdd20c846bba0857ecc0e57f 100644 (file)
@@ -58,6 +58,11 @@ import org.argeo.ArgeoException;
 import org.argeo.jcr.ArgeoNames;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.security.SystemAuthentication;
+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;
 import org.springframework.core.io.Resource;
 import org.springframework.security.Authentication;
 import org.springframework.security.context.SecurityContextHolder;
@@ -98,7 +103,7 @@ public class JackrabbitContainer implements Repository {
 
        private Boolean autocreateWorkspaces = false;
 
-       private Executor systemExecutor;
+       private BundleContext bundleContext;
 
        /**
         * Empty constructor, {@link #init()} should be called after properties have
@@ -356,56 +361,133 @@ public class JackrabbitContainer implements Repository {
                if (isRemote())
                        return;
 
-               Runnable action = new Runnable() {
-                       public void run() {
-                               Session session = null;
-                               try {
-                                       session = login();
-                                       // register namespaces
-                                       if (namespaces.size() > 0) {
-                                               NamespaceHelper namespaceHelper = new NamespaceHelper(
-                                                               session);
-                                               namespaceHelper.registerNamespaces(namespaces);
+               Session session = null;
+               try {
+                       session = login();
+                       // register namespaces
+                       if (namespaces.size() > 0) {
+                               NamespaceHelper namespaceHelper = new NamespaceHelper(session);
+                               namespaceHelper.registerNamespaces(namespaces);
+                       }
+                       // load CND files from classpath or as URL
+                       for (String resUrl : cndFiles) {
+                               boolean classpath;
+                               // if (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 '/'");
+                               // }
+                               // resUrl = "classpath:" + resUrl;
+                               // classpath = true;
+                               // } else {
+                               // classpath = false;
+                               // }
+
+                               if (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 '/'");
                                        }
-                                       // load CND files from classpath or as URL
-                                       for (String resUrl : cndFiles) {
-                                               boolean classpath;
-                                               if (resUrl.startsWith("classpath:")) {
-                                                       resUrl = resUrl.substring("classpath:".length());
-                                                       classpath = true;
-                                               } else if (resUrl.indexOf(':') < 0) {
-                                                       classpath = true;
-                                               } else {
-                                                       classpath = false;
-                                               }
+                                       // resUrl = "classpath:" + resUrl;
+                                       classpath = true;
+                               } else {
+                                       classpath = false;
+                               }
 
-                                               URL url = classpath ? getClass().getClassLoader()
-                                                               .getResource(resUrl) : new URL(resUrl);
+                               // Resource resource =
+                               // resourceLoader.getResource(resUrl);
 
-                                               Reader reader = null;
-                                               try {
-                                                       reader = new InputStreamReader(url.openStream());
-                                                       CndImporter
-                                                                       .registerNodeTypes(reader, session, true);
-                                               } finally {
-                                                       IOUtils.closeQuietly(reader);
+                               // = classpath ? new ClassPathResource(resUrl) : new
+                               // UrlResource(resUrl);
+
+                               URL url;
+                               Bundle dataModelBundle = null;
+                               if (classpath) {
+                                       if (bundleContext != null) {
+                                               Bundle currentBundle = bundleContext.getBundle();
+                                               url = currentBundle.getResource(resUrl);
+                                               if (url != null) {// found
+                                                       dataModelBundle = findDataModelBundle(resUrl);
                                                }
+                                       } else {
+                                               url = getClass().getClassLoader().getResource(resUrl);
                                        }
-                               } catch (Exception e) {
-                                       log.error(
-                                                       "Cannot import node type definitions " + cndFiles,
-                                                       e);
-                                       JcrUtils.discardQuietly(session);
+                                       if (url == null)
+                                               throw new ArgeoException("No " + resUrl
+                                                               + " in the classpath,"
+                                                               + " make sure the containing"
+                                                               + " package is visible.");
+
+                               } else {
+                                       url = new URL(resUrl);
+                               }
+
+                               Reader reader = null;
+                               try {
+                                       reader = new InputStreamReader(url.openStream());
+                                       CndImporter.registerNodeTypes(reader, session, true);
                                } finally {
-                                       JcrUtils.logoutQuietly(session);
+                                       IOUtils.closeQuietly(reader);
                                }
+
+                               if (log.isDebugEnabled())
+                                       log.debug("Data model "
+                                                       + resUrl
+                                                       + (dataModelBundle != null ? ", version "
+                                                                       + dataModelBundle.getVersion()
+                                                                       + ", bundle "
+                                                                       + dataModelBundle.getSymbolicName() : ""));
                        }
-               };
+               } catch (Exception e) {
+                       JcrUtils.discardQuietly(session);
+                       throw new ArgeoException("Cannot import node type definitions "
+                                       + cndFiles, e);
+               } finally {
+                       JcrUtils.logoutQuietly(session);
+               }
+
+       }
+
+       /** Find which OSGi bundle provided the data model resource */
+       protected Bundle findDataModelBundle(String resUrl) {
+               if (resUrl.startsWith("/"))
+                       resUrl = resUrl.substring(1);
+               String pkg = resUrl.substring(0, resUrl.lastIndexOf('/')).replace('/',
+                               '.');
+               ServiceReference paSr = bundleContext
+                               .getServiceReference(PackageAdmin.class.getName());
+               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;
+                               }
+                       }
+               }
 
-               if (systemExecutor != null)
-                       systemExecutor.execute(action);
-               else
-                       action.run();
+               Bundle exportingBundle = null;
+               if (exportedPackage != null) {
+                       exportingBundle = exportedPackage.getExportingBundle();
+               } else {
+                       throw new ArgeoException("No OSGi exporting package found for "
+                                       + resUrl);
+               }
+               return exportingBundle;
        }
 
        /*
@@ -554,7 +636,11 @@ public class JackrabbitContainer implements Repository {
        }
 
        public void setSystemExecutor(Executor systemExecutor) {
-               this.systemExecutor = systemExecutor;
+               throw new IllegalArgumentException(
+                               "systemExecutor is not supported anymore, use:\n"
+                                               + "<bean class=\"org.argeo.security.core.AuthenticatedApplicationContextInitialization\">\n"
+                                               + "\t<property name=\"authenticationManager\" ref=\"authenticationManager\" />\n"
+                                               + "</bean>");
        }
 
        public void setRepository(Repository repository) {
@@ -565,4 +651,8 @@ public class JackrabbitContainer implements Repository {
                        Set<JackrabbitDataModelMigration> dataModelMigrations) {
                this.dataModelMigrations = dataModelMigrations;
        }
+
+       public void setBundleContext(BundleContext bundleContext) {
+               this.bundleContext = bundleContext;
+       }
 }
index 6fe5bf3406bcde3bcb3b5d6de7649d2209e40bb5..5be370fe12a0c4c981e2fa0d4387cc01177a17c9 100644 (file)
@@ -2,6 +2,7 @@ package org.argeo.jackrabbit;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Properties;
 
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
@@ -14,6 +15,7 @@ import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory;
 import org.argeo.ArgeoException;
 import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.jcr.DefaultRepositoryFactory;
+import org.osgi.framework.BundleContext;
 
 /** Repository factory which can access remote Jackrabbit repositories */
 public class JackrabbitRepositoryFactory extends DefaultRepositoryFactory
@@ -21,7 +23,9 @@ public class JackrabbitRepositoryFactory extends DefaultRepositoryFactory
        private final static Log log = LogFactory
                        .getLog(JackrabbitRepositoryFactory.class);
 
-       @SuppressWarnings("rawtypes")
+       private BundleContext bundleContext;
+
+       @SuppressWarnings({ "rawtypes", "unchecked" })
        public Repository getRepository(Map parameters) throws RepositoryException {
                Repository repository = super.getRepository(parameters);
                if (repository != null)
@@ -41,9 +45,24 @@ public class JackrabbitRepositoryFactory extends DefaultRepositoryFactory
                if (repository == null)
                        throw new ArgeoException("Remote Davex repository " + uri
                                        + " not found");
-               log.info("Initialized remote Jackrabbit repository " + repository
-                               + " from uri " + uri);
+               log.info("Initialized remote Jackrabbit repository from uri " + uri);
+
+               if (parameters.containsKey(JCR_REPOSITORY_ALIAS)
+                               && bundleContext != null) {
+                       Properties properties = new Properties();
+                       properties.putAll(parameters);
+                       bundleContext.registerService(Repository.class.getName(),
+                                       repository, properties);
+                       log.info("Registered under alias '"
+                                       + parameters.get(JCR_REPOSITORY_ALIAS)
+                                       + "' the remote JCR repository from uri " + uri);
+               }
 
                return repository;
        }
+
+       public void setBundleContext(BundleContext bundleContext) {
+               this.bundleContext = bundleContext;
+       }
+
 }
index fc9bcaa86356525813fb604eeb65e3e1e561021e..4c8ee90105155bc21393a755cbb73744c38c398c 100644 (file)
@@ -134,8 +134,8 @@ public abstract class ThreadBoundJcrSessionFactory {
                if (activeSessions.size() == 0)
                        return;
 
-               if (log.isDebugEnabled())
-                       log.debug("Cleaning up " + activeSessions.size()
+               if (log.isTraceEnabled())
+                       log.trace("Cleaning up " + activeSessions.size()
                                        + " active JCR sessions...");
 
                deactivate();
@@ -172,8 +172,8 @@ public abstract class ThreadBoundJcrSessionFactory {
                                        Session session = activeSessions.get(thread.getId());
                                        activeSessions.remove(thread.getId());
                                        session.logout();
-                                       if (log.isDebugEnabled())
-                                               log.debug("Cleaned up JCR session (userID="
+                                       if (log.isTraceEnabled())
+                                               log.trace("Cleaned up JCR session (userID="
                                                                + session.getUserID() + ") from dead thread "
                                                                + thread.getId());
                                }