From: Mathieu Baudier Date: Sat, 26 Mar 2011 20:17:11 +0000 (+0000) Subject: Introduce OSAuthentication X-Git-Tag: argeo-commons-2.1.30~1303 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=149023e5969377045847bbecf24b0898b18a67a9;p=lgpl%2Fargeo-commons.git Introduce OSAuthentication git-svn-id: https://svn.argeo.org/commons/trunk@4379 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/basic/runtime/org.argeo.basic.nodeps/src/main/java/org/argeo/OperatingSystem.java b/basic/runtime/org.argeo.basic.nodeps/src/main/java/org/argeo/OperatingSystem.java new file mode 100644 index 000000000..ea073a19d --- /dev/null +++ b/basic/runtime/org.argeo.basic.nodeps/src/main/java/org/argeo/OperatingSystem.java @@ -0,0 +1,20 @@ +package org.argeo; + +/** The current operating system. */ +public class OperatingSystem { + public final static int NIX = 1; + public final static int WINDOWS = 2; + public final static int SOLARIS = 3; + + public final static int os; + static { + String osName = System.getProperty("os.name"); + if (osName.startsWith("Win")) + os = WINDOWS; + else if (osName.startsWith("Solaris")) + os = SOLARIS; + else + os = NIX; + } + +} diff --git a/osgi/dep/org.argeo.osgi.dep.jackrabbit/pom.xml b/osgi/dep/org.argeo.osgi.dep.jackrabbit/pom.xml index 3fee3f3d5..70543eaaf 100644 --- a/osgi/dep/org.argeo.osgi.dep.jackrabbit/pom.xml +++ b/osgi/dep/org.argeo.osgi.dep.jackrabbit/pom.xml @@ -11,33 +11,23 @@ pom Commons OSGi Minimal Jackrabbit - - org.argeo.osgi + org.argeo.commons.osgi org.argeo.osgi.dep.stdruntime 0.3.2-SNAPSHOT pom - org.argeo.dep.osgi org.argeo.dep.osgi.jackrabbit + + - org.argeo.commons.server - org.argeo.server.tika.jackrabbit - ${version.argeo-commons} - - - org.argeo.commons.server - org.argeo.server.ext.jackrabbit - ${version.argeo-commons} - - - org.apache.xalan - com.springsource.org.apache.xalan + com.h2database + com.springsource.org.h2 @@ -56,6 +46,12 @@ pom + + + javax.xml.stream + com.springsource.javax.xml.stream + + org.apache.commons @@ -93,10 +89,6 @@ - - org.springframework - org.springframework.web.servlet - javax.servlet com.springsource.javax.servlet @@ -107,52 +99,7 @@ org.argeo.dep.osgi org.argeo.dep.osgi.tika - - org.argeo.dep.osgi - org.argeo.dep.osgi.pdfbox - - - org.argeo.dep.osgi - org.argeo.dep.osgi.poi - - - org.argeo.dep.osgi - org.argeo.dep.osgi.boilerpipe - - - org.argeo.dep.osgi - org.argeo.dep.osgi.bouncycastle.jdk15 - - - org.argeo.dep.osgi - org.argeo.dep.osgi.drewnoakes.metadata_extractor - - - org.argeo.dep.osgi - org.argeo.dep.osgi.netcdf - - - org.argeo.dep.osgi - org.argeo.dep.osgi.tagsoup - - - - - - net.sourceforge.nekohtml - com.springsource.org.cyberneko.html - - - javax.mail - com.springsource.javax.mail - - - org.apache.xmlbeans - com.springsource.org.apache.xmlbeans - org.dom4j com.springsource.org.dom4j @@ -161,10 +108,6 @@ org.jdom com.springsource.org.jdom - - com.sun.syndication - com.springsource.com.sun.syndication - org.objectweb.asm com.springsource.org.objectweb.asm @@ -177,16 +120,5 @@ org.xmlpull com.springsource.org.xmlpull - - org.argeo.commons.server - org.argeo.server.dep.javax - 0.3.2-SNAPSHOT - pom - - - org.apache.xmlcommons - com.springsource.org.apache.xmlcommons - - \ No newline at end of file diff --git a/osgi/dep/org.argeo.osgi.dep.stdruntime/pom.xml b/osgi/dep/org.argeo.osgi.dep.stdruntime/pom.xml index 0e54720ee..2a0321b97 100644 --- a/osgi/dep/org.argeo.osgi.dep.stdruntime/pom.xml +++ b/osgi/dep/org.argeo.osgi.dep.stdruntime/pom.xml @@ -23,14 +23,5 @@ 0.3.2-SNAPSHOT pom - - - org.springframework.osgi - org.springframework.osgi.core - - - org.springframework.osgi - org.springframework.osgi.extender - \ No newline at end of file diff --git a/osgi/dep/pom.xml b/osgi/dep/pom.xml index 79cc24544..e5d5c7b26 100644 --- a/osgi/dep/pom.xml +++ b/osgi/dep/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.argeo.commons @@ -13,5 +14,36 @@ pom org.argeo.osgi.dep.stdruntime + org.argeo.osgi.dep.jackrabbit + + + + org.argeo.maven.plugins + maven-argeo-osgi-plugin + ${version.maven-argeo-osgi} + + + check-osgi + test + + equinox + + + true + + + + + + + + + + org.argeo.commons.osgi + org.argeo.osgi.boot + 0.3.2-SNAPSHOT + test + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index a1e574584..6faee3717 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ pom 0.3 - 1.1.3 + 1.1.4-SNAPSHOT 0.3.2-SNAPSHOT 0.12.5 3.6.2 @@ -23,6 +23,15 @@ file:///srv/projects/www/commons/site http://projects.argeo.org/commons/site + + basic + osgi + server + eclipse + security + gis + sandbox + ${site.urlBase}/${developmentCycle} scm:svn:https://svn.argeo.org/commons/trunk @@ -68,15 +77,6 @@ limitations under the License. - - basic - osgi - server - eclipse - security - gis - sandbox - diff --git a/security/dep/org.argeo.security.dep.node/pom.xml b/security/dep/org.argeo.security.dep.node/pom.xml index fc48bd591..11e3a584b 100644 --- a/security/dep/org.argeo.security.dep.node/pom.xml +++ b/security/dep/org.argeo.security.dep.node/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 org.argeo.commons.security @@ -44,11 +45,7 @@ 0.3.2-SNAPSHOT pom - - org.apache.xmlcommons - com.springsource.org.apache.xmlcommons - - + org.argeo.commons.security org.argeo.security.core @@ -64,19 +61,37 @@ org.argeo.security.services ${version.argeo-commons} + + org.argeo.commons.security + org.argeo.security.mvc + ${version.argeo-commons} + org.argeo.commons.security org.argeo.security.dao.ldap ${version.argeo-commons} - + - org.argeo.commons.security - org.argeo.security.dep.ads - 0.3.2-SNAPSHOT - pom + org.apache.xmlcommons + com.springsource.org.apache.xmlcommons + + + org.apache.xalan + com.springsource.org.apache.xalan + + + + org.springframework.osgi + org.springframework.osgi.web.extender + + + org.springframework.osgi + org.springframework.osgi.web + + org.argeo.commons.server @@ -89,14 +104,6 @@ org.argeo.server.webextender 0.3.2-SNAPSHOT - - org.springframework.osgi - org.springframework.osgi.web.extender - - - org.springframework.osgi - org.springframework.osgi.web - org.argeo.commons.server @@ -125,12 +132,6 @@ org.argeo.server.jcr.mvc 0.3.2-SNAPSHOT - - org.argeo.commons.server - org.argeo.server.dep.jackrabbit.server - 0.3.2-SNAPSHOT - pom - org.argeo.commons.server org.argeo.jackrabbit.webapp @@ -166,5 +167,13 @@ org.postgresql com.springsource.org.postgresql.jdbc3 + + + org.argeo.commons.security + org.argeo.security.dep.ads + 0.3.2-SNAPSHOT + pom + test + diff --git a/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao-osgi.xml b/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao-osgi.xml index 0c2706d03..4b15210c0 100644 --- a/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao-osgi.xml +++ b/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao-osgi.xml @@ -14,11 +14,14 @@ cardinality="0..1"> + + + - - + + \ No newline at end of file diff --git a/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao.xml b/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao.xml index 43f8520a7..ab4104f82 100644 --- a/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao.xml +++ b/security/modules/org.argeo.security.dao.jackrabbit/META-INF/spring/jcrsecuritydao.xml @@ -6,5 +6,7 @@ - + + + \ No newline at end of file diff --git a/security/modules/org.argeo.security.services/META-INF/spring/services.xml b/security/modules/org.argeo.security.services/META-INF/spring/services.xml index 3a0dca745..1a56b8523 100644 --- a/security/modules/org.argeo.security.services/META-INF/spring/services.xml +++ b/security/modules/org.argeo.security.services/META-INF/spring/services.xml @@ -29,6 +29,7 @@ + diff --git a/security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml b/security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml index f454d7a3a..5714e0e19 100644 --- a/security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml +++ b/security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml @@ -8,4 +8,9 @@ scope="prototype"> + + + + diff --git a/security/plugins/org.argeo.security.equinox/plugin.xml b/security/plugins/org.argeo.security.equinox/plugin.xml index 78f0d9cb1..2e63e17a4 100644 --- a/security/plugins/org.argeo.security.equinox/plugin.xml +++ b/security/plugins/org.argeo.security.equinox/plugin.xml @@ -1,30 +1,30 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/OsSpringLoginModule.java b/security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/OsSpringLoginModule.java new file mode 100644 index 000000000..47d3e5bfd --- /dev/null +++ b/security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/OsSpringLoginModule.java @@ -0,0 +1,67 @@ +package org.argeo.security.equinox; + +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.login.LoginException; + +import org.argeo.security.OsAuthenticationToken; +import org.springframework.security.Authentication; +import org.springframework.security.AuthenticationManager; +import org.springframework.security.context.SecurityContextHolder; +import org.springframework.security.providers.jaas.SecurityContextLoginModule; + +/** Login module which caches one subject per thread. */ +public class OsSpringLoginModule extends SecurityContextLoginModule { + // private final static Log log = + // LogFactory.getLog(OsSpringLoginModule.class); + + private AuthenticationManager authenticationManager; + + private Subject subject; + + public OsSpringLoginModule() { + + } + + @SuppressWarnings("rawtypes") + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) { + super.initialize(subject, callbackHandler, sharedState, options); + this.subject = subject; + } + + public boolean login() throws LoginException { + // thread already logged in + if (SecurityContextHolder.getContext().getAuthentication() != null) + return super.login(); + + OsAuthenticationToken oat = new OsAuthenticationToken(); + Authentication authentication = authenticationManager.authenticate(oat); + registerAuthentication(authentication); + return super.login(); + } + + @Override + public boolean logout() throws LoginException { + subject.getPrincipals().clear(); + return super.logout(); + } + + /** + * Register an {@link Authentication} in the security context. + * + * @param authentication + * has to implement {@link Authentication}. + */ + protected void registerAuthentication(Object authentication) { + SecurityContextHolder.getContext().setAuthentication( + (Authentication) authentication); + } + + public void setAuthenticationManager( + AuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + } +} diff --git a/security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java b/security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java index 0e5984532..c35416d99 100644 --- a/security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java +++ b/security/plugins/org.argeo.security.equinox/src/main/java/org/argeo/security/equinox/SpringLoginModule.java @@ -15,7 +15,6 @@ import org.apache.commons.logging.LogFactory; import org.argeo.security.SiteAuthenticationToken; import org.springframework.security.Authentication; import org.springframework.security.AuthenticationManager; -import org.springframework.security.BadCredentialsException; import org.springframework.security.context.SecurityContextHolder; import org.springframework.security.providers.jaas.SecurityContextLoginModule; @@ -97,20 +96,20 @@ public class SpringLoginModule extends SecurityContextLoginModule { SiteAuthenticationToken credentials = new SiteAuthenticationToken( username, password, null, workspace); - try { - Authentication authentication = authenticationManager - .authenticate(credentials); - registerAuthentication(authentication); - boolean res = super.login(); - return res; - } catch (BadCredentialsException bce) { - throw bce; - } catch (Exception e) { - LoginException loginException = new LoginException( - "Bad credentials"); - loginException.initCause(e); - throw loginException; - } + // try { + Authentication authentication = authenticationManager + .authenticate(credentials); + registerAuthentication(authentication); + boolean res = super.login(); + return res; + // } catch (BadCredentialsException bce) { + // throw bce; + // } catch (LoginException e) { + // // LoginException loginException = new LoginException( + // // "Bad credentials"); + // // loginException.initCause(e); + // throw e; + // } } @Override diff --git a/security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt b/security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt index b6cbaa655..5e0e4d3b2 100644 --- a/security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt +++ b/security/plugins/org.argeo.security.ui.rcp/META-INF/jaas_default.txt @@ -1,14 +1,13 @@ -UNIX { - org.eclipse.equinox.security.auth.module.ExtensionLoginModule sufficient +NIX { + org.eclipse.equinox.security.auth.module.ExtensionLoginModule requisite extensionId="org.argeo.security.equinox.unixLoginModule"; + org.eclipse.equinox.security.auth.module.ExtensionLoginModule required + extensionId="org.argeo.security.equinox.osSpringLoginModule"; }; -SPRING { - org.eclipse.equinox.security.auth.module.ExtensionLoginModule sufficient - extensionId="org.argeo.security.equinox.springLoginModule"; +WINDOWS { + org.eclipse.equinox.security.auth.module.ExtensionLoginModule requisite + extensionId="org.argeo.security.equinox.ntLoginModule"; + org.eclipse.equinox.security.auth.module.ExtensionLoginModule required + extensionId="org.argeo.security.equinox.osSpringLoginModule"; }; - -SPRING_SECURITY_CONTEXT { - org.eclipse.equinox.security.auth.module.ExtensionLoginModule sufficient - extensionId="org.argeo.security.equinox.springSecurityContextLoginModule"; -}; \ No newline at end of file diff --git a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java index 2a9dd0c25..3da1bc7b4 100644 --- a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java +++ b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/AbstractSecureApplication.java @@ -7,96 +7,112 @@ import javax.security.auth.login.LoginException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.eclipse.ui.dialogs.Error; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; +import org.argeo.OperatingSystem; import org.eclipse.equinox.app.IApplication; import org.eclipse.equinox.app.IApplicationContext; -import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.equinox.security.auth.ILoginContext; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.application.WorkbenchAdvisor; /** - * Common base class for authenticated access to the Eclipse UI framework (RAP - * and RCP) + * RCP workbench initialization */ public abstract class AbstractSecureApplication implements IApplication { private static final Log log = LogFactory .getLog(AbstractSecureApplication.class); - protected abstract WorkbenchAdvisor createWorkbenchAdvisor(); + protected WorkbenchAdvisor createWorkbenchAdvisor(String username) { + return new SecureWorkbenchAdvisor(username); + } public Object start(IApplicationContext context) throws Exception { - - Integer returnCode = null; - Display display = PlatformUI.createDisplay(); + // wait for the system to be initialized try { - Subject subject = null; - Boolean retry = true; - while (retry) { - try { - SecureApplicationActivator.getLoginContext().login(); - subject = SecureApplicationActivator.getLoginContext() - .getSubject(); - retry = false; - } catch (LoginException e) { - Error.show("Cannot login", e); - retry = true; - } catch (Exception e) { - Error.show("Unexpected exception while trying to login", e); - retry = false; - } - } + Thread.sleep(3000); + } catch (Exception e2) { + // silent + } + + // choose login context + final ILoginContext loginContext; + if (OperatingSystem.os == OperatingSystem.WINDOWS) + loginContext = SecureApplicationActivator + .createLoginContext(SecureApplicationActivator.CONTEXT_WINDOWS); + else + loginContext = SecureApplicationActivator + .createLoginContext(SecureApplicationActivator.CONTEXT_NIX); - if (subject == null) { - // IStatus status = new Status(IStatus.ERROR, - // "org.argeo.security.application", "Login is mandatory", - // loginException); - // ErrorDialog.openError(null, "Error", "Shutdown...", status); - // return status.getSeverity(); + final Display display = PlatformUI.createDisplay(); - // TODO: log as anonymous + Subject subject = null; + try { + loginContext.login(); + subject = loginContext.getSubject(); + } catch (LoginException e) { + log.error("Error when logging in.", e); + display.dispose(); + try { + Thread.sleep(2000); + } catch (InterruptedException e1) { + // silent } + return null; + } - if (subject != null) { - returnCode = (Integer) Subject.doAs(subject, - getRunAction(display)); - SecureApplicationActivator.getLoginContext().logout(); - return processReturnCode(returnCode); - } else { - return -1; + // identify after successful login + if (log.isDebugEnabled()) + log.debug("subject=" + subject); + final String username = subject.getPrincipals().iterator().next() + .getName(); + if (log.isDebugEnabled()) + log.debug(username + " logged in"); + display.disposeExec(new Runnable() { + public void run() { + log.debug("Display disposed"); + logout(loginContext, username); } + }); + + try { + PrivilegedAction privilegedAction = new PrivilegedAction() { + public Object run() { + int result = PlatformUI.createAndRunWorkbench(display, + createWorkbenchAdvisor(username)); + return new Integer(result); + } + }; + + Integer returnCode = (Integer) Subject.doAs(subject, + privilegedAction); + logout(loginContext, username); + return processReturnCode(returnCode); } catch (Exception e) { - // e.printStackTrace(); - IStatus status = new Status(IStatus.ERROR, - "org.argeo.security.rcp", "Login failed", e); - ErrorDialog.openError(null, "Error", "Shutdown...", status); - return returnCode; + if (subject != null) + logout(loginContext, username); + log.error("Unexpected error", e); } finally { display.dispose(); } + return null; } protected Integer processReturnCode(Integer returnCode) { - return returnCode; + if (returnCode == PlatformUI.RETURN_RESTART) + return IApplication.EXIT_RESTART; + else + return IApplication.EXIT_OK; } - @SuppressWarnings("rawtypes") - private PrivilegedAction getRunAction(final Display display) { - return new PrivilegedAction() { - - public Object run() { - int result = createAndRunWorkbench(display); - return new Integer(result); - } - }; - } - - protected Integer createAndRunWorkbench(Display display) { - return PlatformUI.createAndRunWorkbench(display, - createWorkbenchAdvisor()); + static void logout(ILoginContext secureContext, String username) { + try { + secureContext.logout(); + log.info("Logged out " + (username != null ? username : "") + + " (THREAD=" + Thread.currentThread().getId() + ")"); + } catch (LoginException e) { + log.error("Erorr when logging out", e); + } } public void stop() { @@ -120,10 +136,6 @@ public abstract class AbstractSecureApplication implements IApplication { if (log.isDebugEnabled()) log.debug("workbench stopped"); - // String username = CurrentUser.getUsername(); - // if (log.isDebugEnabled()) - // log.debug("workbench stopped, logged in as " + username); - } } diff --git a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureApplicationActivator.java b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureApplicationActivator.java index 53d2a7570..1c8bd7c25 100644 --- a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureApplicationActivator.java +++ b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureApplicationActivator.java @@ -7,23 +7,24 @@ import org.eclipse.equinox.security.auth.LoginContextFactory; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +/** Activator able to create {@link ILoginContext} */ public class SecureApplicationActivator implements BundleActivator { - public final static String CONTEXT_SPRING = "SPRING"; + public final static String CONTEXT_NIX = "NIX"; + public final static String CONTEXT_WINDOWS = "WINDOWS"; private static final String JAAS_CONFIG_FILE = "/META-INF/jaas_default.txt"; - private static ILoginContext loginContext = null; + private static BundleContext bundleContext; public void start(BundleContext bundleContext) throws Exception { - URL configUrl = bundleContext.getBundle().getEntry(JAAS_CONFIG_FILE); - loginContext = LoginContextFactory.createContext(CONTEXT_SPRING, - configUrl); + SecureApplicationActivator.bundleContext = bundleContext; } public void stop(BundleContext context) throws Exception { } - static ILoginContext getLoginContext() { - return loginContext; + static ILoginContext createLoginContext(String context) { + URL configUrl = bundleContext.getBundle().getEntry(JAAS_CONFIG_FILE); + return LoginContextFactory.createContext(context, configUrl); } } diff --git a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureRcp.java b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureRcp.java index cd1d518b4..dbf442fb5 100644 --- a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureRcp.java +++ b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureRcp.java @@ -1,21 +1,5 @@ package org.argeo.security.ui.rcp; -import org.eclipse.equinox.app.IApplication; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.application.WorkbenchAdvisor; public class SecureRcp extends AbstractSecureApplication { - - @Override - protected WorkbenchAdvisor createWorkbenchAdvisor() { - return new SecureWorkbenchAdvisor(); - } - - protected Integer processReturnCode(Integer returnCode) { - if (returnCode == PlatformUI.RETURN_RESTART) - return IApplication.EXIT_RESTART; - else - return IApplication.EXIT_OK; - } - } diff --git a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java index 191a83aef..bca01e714 100644 --- a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java +++ b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchAdvisor.java @@ -5,16 +5,21 @@ import org.eclipse.ui.application.WorkbenchAdvisor; import org.eclipse.ui.application.WorkbenchWindowAdvisor; public class SecureWorkbenchAdvisor extends WorkbenchAdvisor { - static final String DEFAULT_PERSPECTIVE_ID = "org.argeo.security.ui.adminSecurityPerspective"; //$NON-NLS-1$ - public final static String INITIAL_PERSPECTIVE_PROPERTY = "org.argeo.security.ui.initialPerspective"; + + private final String username; private String initialPerspective = System.getProperty( INITIAL_PERSPECTIVE_PROPERTY, DEFAULT_PERSPECTIVE_ID); + public SecureWorkbenchAdvisor(String username) { + super(); + this.username = username; + } + public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor( IWorkbenchWindowConfigurer configurer) { - return new SecureWorkbenchWindowAdvisor(configurer); + return new SecureWorkbenchWindowAdvisor(configurer, username); } public String getInitialWindowPerspectiveId() { diff --git a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java index e4edf78f1..4847bcfdd 100644 --- a/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java +++ b/security/plugins/org.argeo.security.ui.rcp/src/main/java/org/argeo/security/ui/rcp/SecureWorkbenchWindowAdvisor.java @@ -7,9 +7,12 @@ import org.eclipse.ui.application.IWorkbenchWindowConfigurer; import org.eclipse.ui.application.WorkbenchWindowAdvisor; public class SecureWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { + private final String username; - public SecureWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) { + public SecureWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer, + String username) { super(configurer); + this.username = username; } public ActionBarAdvisor createActionBarAdvisor( @@ -25,8 +28,7 @@ public class SecureWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { configurer.setShowStatusLine(false); configurer.setShowPerspectiveBar(true); - configurer.setTitle("Argeo Secure UI"); //$NON-NLS-1$ + configurer.setTitle("Argeo UI - " + username); //$NON-NLS-1$ } - } diff --git a/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/internal/CurrentUser.java b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/internal/CurrentUser.java index 638eb03a5..ed50d1e3c 100644 --- a/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/internal/CurrentUser.java +++ b/security/plugins/org.argeo.security.ui/src/main/java/org/argeo/security/ui/internal/CurrentUser.java @@ -23,12 +23,16 @@ public class CurrentUser { } public final static Set roles() { - Principal principal = getSubject().getPrincipals(Authentication.class) - .iterator().next(); - Authentication authentication = (Authentication) principal; Set roles = Collections.synchronizedSet(new HashSet()); - for (GrantedAuthority ga : authentication.getAuthorities()) { - roles.add(ga.getAuthority()); + + Set authens = getSubject().getPrincipals( + Authentication.class); + if (authens != null && !authens.isEmpty()) { + Principal principal = authens.iterator().next(); + Authentication authentication = (Authentication) principal; + for (GrantedAuthority ga : authentication.getAuthorities()) { + roles.add(ga.getAuthority()); + } } return Collections.unmodifiableSet(roles); } diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/OsAuthenticationToken.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/OsAuthenticationToken.java new file mode 100644 index 000000000..9fba6f054 --- /dev/null +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/OsAuthenticationToken.java @@ -0,0 +1,157 @@ +package org.argeo.security; + +import java.security.AccessController; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import javax.security.auth.Subject; + +import org.argeo.ArgeoException; +import org.argeo.OperatingSystem; +import org.springframework.security.Authentication; +import org.springframework.security.GrantedAuthority; +import org.springframework.security.GrantedAuthorityImpl; +import org.springframework.security.userdetails.UserDetails; + +/** Abstracts principals provided by com.sun.security.auth.module login modules. */ +public class OsAuthenticationToken implements Authentication { + private static final long serialVersionUID = -7544626794250917244L; + + final Class osUserPrincipalClass; + final Class osUserIdPrincipalClass; + final Class osGroupIdPrincipalClass; + + private List grantedAuthorities; + + private UserDetails details; + + /** Request */ + public OsAuthenticationToken(GrantedAuthority[] grantedAuthorities) { + this.grantedAuthorities = grantedAuthorities != null ? Arrays + .asList(grantedAuthorities) : null; + ClassLoader cl = getClass().getClassLoader(); + switch (OperatingSystem.os) { + case OperatingSystem.WINDOWS: + osUserPrincipalClass = getPrincipalClass(cl, + "com.sun.security.auth.NTUserPrincipal"); + osUserIdPrincipalClass = getPrincipalClass(cl, + "com.sun.security.auth.NTSidUserPrincipal"); + osGroupIdPrincipalClass = getPrincipalClass(cl, + "com.sun.security.auth.NTSidGroupPrincipal"); + break; + case OperatingSystem.NIX: + osUserPrincipalClass = getPrincipalClass(cl, + "com.sun.security.auth.UnixPrincipal"); + osUserIdPrincipalClass = getPrincipalClass(cl, + "com.sun.security.auth.UnixNumericUserPrincipal"); + osGroupIdPrincipalClass = getPrincipalClass(cl, + "com.sun.security.auth.UnixNumericGroupPrincipal"); + break; + case OperatingSystem.SOLARIS: + osUserPrincipalClass = getPrincipalClass(cl, + "com.sun.security.auth.SolarisPrincipal"); + osUserIdPrincipalClass = getPrincipalClass(cl, + "com.sun.security.auth.SolarisNumericUserPrincipal"); + osGroupIdPrincipalClass = getPrincipalClass(cl, + "com.sun.security.auth.SolarisNumericGroupPrincipal"); + break; + + default: + throw new ArgeoException("Unsupported operating system " + + OperatingSystem.os); + } + + } + + /** Authenticated */ + public OsAuthenticationToken() { + this(null); + } + + public String getName() { + return getUser().getName(); + } + + public GrantedAuthority[] getAuthorities() { + // grantedAuthorities should not be null at this stage + List gas = new ArrayList( + grantedAuthorities); + for (Principal groupPrincipal : getGroupsIds()) { + gas.add(new GrantedAuthorityImpl("OSGROUP_" + + groupPrincipal.getName())); + } + return gas.toArray(new GrantedAuthority[gas.size()]); + } + + public UserDetails getDetails() { + return details; + } + + public void setDetails(UserDetails details) { + this.details = details; + } + + public boolean isAuthenticated() { + return grantedAuthorities != null; + } + + public void setAuthenticated(boolean isAuthenticated) + throws IllegalArgumentException { + if (grantedAuthorities != null) + grantedAuthorities.clear(); + grantedAuthorities = null; + } + + @SuppressWarnings("unchecked") + protected static Class getPrincipalClass( + ClassLoader cl, String className) { + try { + return (Class) cl.loadClass(className); + } catch (ClassNotFoundException e) { + throw new ArgeoException("Cannot load principal class", e); + } + } + + public Object getPrincipal() { + return getUser(); + } + + public Principal getUser() { + Subject subject = Subject.getSubject(AccessController.getContext()); + Set userPrincipals = subject + .getPrincipals(osUserPrincipalClass); + if (userPrincipals == null || userPrincipals.size() == 0) + throw new ArgeoException("No OS principal"); + if (userPrincipals.size() > 1) + throw new ArgeoException("More than one OS principal"); + Principal user = userPrincipals.iterator().next(); + return user; + } + + public Principal getUserId() { + Subject subject = Subject.getSubject(AccessController.getContext()); + Set userIdsPrincipals = subject + .getPrincipals(osUserIdPrincipalClass); + if (userIdsPrincipals == null || userIdsPrincipals.size() == 0) + throw new ArgeoException("No user id principal"); + if (userIdsPrincipals.size() > 1) + throw new ArgeoException("More than one user id principal"); + Principal userId = userIdsPrincipals.iterator().next(); + return userId; + } + + public Set getGroupsIds() { + Subject subject = Subject.getSubject(AccessController.getContext()); + return (Set) subject + .getPrincipals(osGroupIdPrincipalClass); + } + + public Object getCredentials() { + return ""; + } + +} diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/OsAuthenticationProvider.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/OsAuthenticationProvider.java new file mode 100644 index 000000000..e9c83839f --- /dev/null +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/core/OsAuthenticationProvider.java @@ -0,0 +1,52 @@ +package org.argeo.security.core; + +import java.util.ArrayList; +import java.util.List; + +import org.argeo.security.OsAuthenticationToken; +import org.springframework.security.Authentication; +import org.springframework.security.AuthenticationException; +import org.springframework.security.GrantedAuthority; +import org.springframework.security.GrantedAuthorityImpl; +import org.springframework.security.providers.AuthenticationProvider; + +/** Validates an OS authentication. */ +public class OsAuthenticationProvider implements AuthenticationProvider { + private String osUserRole = "ROLE_OS_USER"; + private String userRole = "ROLE_USER"; + private String adminRole = "ROLE_ADMIN"; + + private Boolean isAdmin = true; + + public Authentication authenticate(Authentication authentication) + throws AuthenticationException { + if (authentication instanceof OsAuthenticationToken) { + List auths = new ArrayList(); + auths.add(new GrantedAuthorityImpl(osUserRole)); + auths.add(new GrantedAuthorityImpl(userRole)); + if (isAdmin) + auths.add(new GrantedAuthorityImpl(adminRole)); + return new OsAuthenticationToken( + auths.toArray(new GrantedAuthority[auths.size()])); + } + return null; + } + + @SuppressWarnings("rawtypes") + public boolean supports(Class authentication) { + return OsAuthenticationToken.class.isAssignableFrom(authentication); + } + + public void setOsUserRole(String osUserRole) { + this.osUserRole = osUserRole; + } + + public void setAdminRole(String adminRole) { + this.adminRole = adminRole; + } + + public void setIsAdmin(Boolean isAdmin) { + this.isAdmin = isAdmin; + } + +} diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationProvider.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationProvider.java index ce7d91812..9791da8a0 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationProvider.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/JcrAuthenticationProvider.java @@ -79,21 +79,20 @@ public class JcrAuthenticationProvider implements AuthenticationProvider { } /** Builds user details based on the authentication and the user home. */ - protected UserDetails getUserDetails(Node userHome, - JcrAuthenticationToken authen) { + protected UserDetails getUserDetails(Node userHome, Authentication authen) { try { // TODO: loads enabled, locked, etc. from the home node. return new JcrUserDetails(userHome.getPath(), authen.getPrincipal() .toString(), authen.getCredentials().toString(), - isEnabled(userHome), - true, true, true, authen.getAuthorities()); + isEnabled(userHome), true, true, true, + authen.getAuthorities()); } catch (Exception e) { throw new ArgeoException("Cannot get user details for " + userHome, e); } } - - protected Boolean isEnabled(Node userHome){ + + protected Boolean isEnabled(Node userHome) { return true; } diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java new file mode 100644 index 000000000..192d2fdb2 --- /dev/null +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/OsJcrAuthenticationProvider.java @@ -0,0 +1,96 @@ +package org.argeo.security.jcr; + +import java.util.Map; +import java.util.concurrent.Executor; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.RepositoryFactory; +import javax.jcr.Session; + +import org.argeo.ArgeoException; +import org.argeo.jcr.JcrUtils; +import org.argeo.security.OsAuthenticationToken; +import org.argeo.security.core.OsAuthenticationProvider; +import org.springframework.security.Authentication; +import org.springframework.security.AuthenticationException; +import org.springframework.security.userdetails.UserDetails; + +public class OsJcrAuthenticationProvider extends OsAuthenticationProvider { + private RepositoryFactory repositoryFactory; + private Executor systemExecutor; + private String homeBasePath = "/home"; + private String repositoryAlias = "node"; + private String workspace = null; + + public Authentication authenticate(Authentication authentication) + throws AuthenticationException { + final OsAuthenticationToken authen = (OsAuthenticationToken) super + .authenticate(authentication); + systemExecutor.execute(new Runnable() { + public void run() { + try { + Session session = JcrUtils.getRepositoryByAlias( + repositoryFactory, repositoryAlias) + .login(workspace); + Node userHome = JcrUtils.getUserHome(session, + authen.getName()); + if (userHome == null) + JcrUtils.createUserHome(session, homeBasePath, + authen.getName()); + authen.setDetails(getUserDetails(userHome, authen)); + } catch (RepositoryException e) { + throw new ArgeoException( + "Unexpected exception when synchronizing OS and JCR security ", + e); + } + } + }); + return authen; + } + + /** Builds user details based on the authentication and the user home. */ + protected UserDetails getUserDetails(Node userHome, Authentication authen) { + try { + // TODO: loads enabled, locked, etc. from the home node. + return new JcrUserDetails(userHome.getPath(), authen.getPrincipal() + .toString(), authen.getCredentials().toString(), + isEnabled(userHome), true, true, true, + authen.getAuthorities()); + } catch (Exception e) { + throw new ArgeoException("Cannot get user details for " + userHome, + e); + } + } + + protected Boolean isEnabled(Node userHome) { + return true; + } + + public void register(RepositoryFactory repositoryFactory, + Map parameters) { + this.repositoryFactory = repositoryFactory; + } + + public void unregister(RepositoryFactory repositoryFactory, + Map parameters) { + this.repositoryFactory = null; + } + + public void setSystemExecutor(Executor systemExecutor) { + this.systemExecutor = systemExecutor; + } + + public void setHomeBasePath(String homeBasePath) { + this.homeBasePath = homeBasePath; + } + + public void setRepositoryAlias(String repositoryAlias) { + this.repositoryAlias = repositoryAlias; + } + + public void setWorkspace(String workspace) { + this.workspace = workspace; + } + +} diff --git a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/SecureThreadBoundSession.java b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/SecureThreadBoundSession.java index aa3b15679..db2cfccbc 100644 --- a/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/SecureThreadBoundSession.java +++ b/security/runtime/org.argeo.security.core/src/main/java/org/argeo/security/jcr/SecureThreadBoundSession.java @@ -5,14 +5,30 @@ import javax.jcr.Session; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.jcr.ThreadBoundJcrSessionFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; import org.springframework.security.Authentication; import org.springframework.security.context.SecurityContextHolder; import org.springframework.security.userdetails.UserDetails; -public class SecureThreadBoundSession extends ThreadBoundJcrSessionFactory { +/** + * Thread bounded JCR session factory which checks authentication and is + * autoconfigured in Spring. + */ +public class SecureThreadBoundSession extends ThreadBoundJcrSessionFactory + implements FactoryBean, InitializingBean, DisposableBean { private final static Log log = LogFactory .getLog(SecureThreadBoundSession.class); + public void afterPropertiesSet() throws Exception { + init(); + } + + public void destroy() throws Exception { + dispose(); + } + @Override protected Session preCall(Session session) { Authentication authentication = SecurityContextHolder.getContext() diff --git a/security/runtime/org.argeo.security.mvc/pom.xml b/security/runtime/org.argeo.security.mvc/pom.xml index 59d96e801..26c93fe49 100644 --- a/security/runtime/org.argeo.security.mvc/pom.xml +++ b/security/runtime/org.argeo.security.mvc/pom.xml @@ -1,9 +1,10 @@ - + 4.0.0 org.argeo.commons.security runtime - 0.2.3-SNAPSHOT + 0.3.2-SNAPSHOT .. org.argeo.security.mvc @@ -42,14 +43,14 @@ org.argeo.commons.server org.argeo.server.core - 0.2.3-SNAPSHOT + 0.3.2-SNAPSHOT org.argeo.commons.security org.argeo.security.core - 0.2.3-SNAPSHOT + 0.3.2-SNAPSHOT diff --git a/security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/ArgeoUserInterceptor.java b/security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/ArgeoUserInterceptor.java index bc8807d37..a9be56d38 100644 --- a/security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/ArgeoUserInterceptor.java +++ b/security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/ArgeoUserInterceptor.java @@ -19,21 +19,21 @@ package org.argeo.security.mvc; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.argeo.security.ArgeoSecurityService; +import org.argeo.security.UserAdminService; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; /** Add the current argeo user as an attribute to the request. */ public class ArgeoUserInterceptor extends HandlerInterceptorAdapter { - private ArgeoSecurityService securityService; + private UserAdminService securityService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - request.setAttribute("argeoUser", securityService.getCurrentUser()); + //request.setAttribute("argeoUser", securityService.getCurrentUser()); return super.preHandle(request, response, handler); } - public void setSecurityService(ArgeoSecurityService securityService) { + public void setSecurityService(UserAdminService securityService) { this.securityService = securityService; } diff --git a/security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/UsersRolesController.java b/security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/UsersRolesController.java index f2da2be6a..2ce770c46 100644 --- a/security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/UsersRolesController.java +++ b/security/runtime/org.argeo.security.mvc/src/main/java/org/argeo/security/mvc/UsersRolesController.java @@ -16,159 +16,120 @@ package org.argeo.security.mvc; -import java.io.Reader; -import java.util.Set; - -import org.argeo.security.ArgeoSecurityService; -import org.argeo.security.ArgeoUser; -import org.argeo.security.SimpleArgeoUser; -import org.argeo.server.BooleanAnswer; -import org.argeo.server.Deserializer; -import org.argeo.server.ServerAnswer; import org.argeo.server.mvc.MvcConstants; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; @Controller public class UsersRolesController implements MvcConstants { - // private final static Log log = LogFactory - // .getLog(UsersRolesController.class); - - // private String digestType = "SHA"; - - private ArgeoSecurityService securityService; - - private Deserializer userDeserializer = null; +// private ArgeoSecurityService securityService; +// private Deserializer userDeserializer = null; /* USER */ - @RequestMapping("/getCredentials.*") - @ModelAttribute("user") - public ArgeoUser getCredentials() { - ArgeoUser argeoUser = securityService.getCurrentUser(); - if (argeoUser == null) - return new SimpleArgeoUser(); - else - return argeoUser; - } - - @RequestMapping("/getUsersList.*") - @ModelAttribute("users") - public Set getUsersList() { - return securityService.listUsers(); - } - - @RequestMapping("/userExists.*") - public BooleanAnswer userExists(@RequestParam("username") String username) { - return new BooleanAnswer(securityService.userExists(username)); - } - - @RequestMapping("/createUser.*") - @ModelAttribute("user") - public ArgeoUser createUser(Reader reader) { - ArgeoUser user = userDeserializer.deserialize(reader, - SimpleArgeoUser.class); - // cleanUserBeforeCreate(user); - securityService.newUser(user); - return securityService.getUser(user.getUsername()); - } - - @RequestMapping("/updateUser.*") - @ModelAttribute("user") - public ArgeoUser updateUser(Reader reader) { - ArgeoUser user = userDeserializer.deserialize(reader, - SimpleArgeoUser.class); - securityService.updateUser(user); - return securityService.getUser(user.getUsername()); - } - - @RequestMapping("/updateUserSelf.*") - @ModelAttribute("user") - /** Will only update the user natures.*/ - public ArgeoUser updateUserSelf(Reader reader) { - ArgeoUser user = securityService.getCurrentUser(); - ArgeoUser userForNatures = userDeserializer.deserialize(reader, - SimpleArgeoUser.class); - user.updateUserNatures(userForNatures.getUserNatures()); - securityService.updateUser(user); - return securityService.getUser(user.getUsername()); - } - - @RequestMapping("/deleteUser.*") - public ServerAnswer deleteUser(@RequestParam("username") String username) { - securityService.deleteUser(username); - return ServerAnswer.ok("User " + username + " deleted"); - } - - @RequestMapping("/getUserDetails.*") - @ModelAttribute("user") - public ArgeoUser getUserDetails(@RequestParam("username") String username) { - return securityService.getUser(username); - } +// @RequestMapping("/getCredentials.*") +// @ModelAttribute("user") +// public ArgeoUser getCredentials() { +// ArgeoUser argeoUser = securityService.getCurrentUser(); +// if (argeoUser == null) +// return new SimpleArgeoUser(); +// else +// return argeoUser; +// } +// +// @RequestMapping("/getUsersList.*") +// @ModelAttribute("users") +// public Set getUsersList() { +// return securityService.listUsers(); +// } +// +// @RequestMapping("/userExists.*") +// public BooleanAnswer userExists(@RequestParam("username") String username) { +// return new BooleanAnswer(securityService.userExists(username)); +// } +// +// @RequestMapping("/createUser.*") +// @ModelAttribute("user") +// public ArgeoUser createUser(Reader reader) { +// ArgeoUser user = userDeserializer.deserialize(reader, +// SimpleArgeoUser.class); +// securityService.newUser(user); +// return securityService.getUser(user.getUsername()); +// } +// +// @RequestMapping("/updateUser.*") +// @ModelAttribute("user") +// public ArgeoUser updateUser(Reader reader) { +// ArgeoUser user = userDeserializer.deserialize(reader, +// SimpleArgeoUser.class); +// securityService.updateUser(user); +// return securityService.getUser(user.getUsername()); +// } +// +// @RequestMapping("/updateUserSelf.*") +// @ModelAttribute("user") +// /** Will only update the user natures.*/ +// public ArgeoUser updateUserSelf(Reader reader) { +// ArgeoUser user = securityService.getCurrentUser(); +// ArgeoUser userForNatures = userDeserializer.deserialize(reader, +// SimpleArgeoUser.class); +// user.updateUserNatures(userForNatures.getUserNatures()); +// securityService.updateUser(user); +// return securityService.getUser(user.getUsername()); +// } +// +// @RequestMapping("/deleteUser.*") +// public ServerAnswer deleteUser(@RequestParam("username") String username) { +// securityService.deleteUser(username); +// return ServerAnswer.ok("User " + username + " deleted"); +// } +// +// @RequestMapping("/getUserDetails.*") +// @ModelAttribute("user") +// public ArgeoUser getUserDetails(@RequestParam("username") String username) { +// return securityService.getUser(username); +// } /* ROLE */ - @RequestMapping("/getRolesList.*") - @ModelAttribute("roles") - public Set getEditableRolesList() { - return securityService.listEditableRoles(); - } - - @RequestMapping("/createRole.*") - public ServerAnswer createRole(@RequestParam("role") String role) { - securityService.newRole(role); - return ServerAnswer.ok("Role " + role + " created"); - } - - @RequestMapping("/deleteRole.*") - public ServerAnswer deleteRole(@RequestParam("role") String role) { - securityService.deleteRole(role); - return ServerAnswer.ok("Role " + role + " deleted"); - } - - @RequestMapping("/updateUserPassword.*") - public ServerAnswer updateUserPassword( - @RequestParam("username") String username, - @RequestParam("password") String password) { - securityService.updateUserPassword(username, password); - return ServerAnswer.ok("Password updated for user " + username); - } - - @RequestMapping("/updatePassword.*") - public ServerAnswer updatePassword( - @RequestParam("oldPassword") String oldPassword, - @RequestParam("password") String password) { - securityService.updateCurrentUserPassword(oldPassword, password); - return ServerAnswer.ok("Password updated"); - } - - // protected String digestIfNecessary(String str) { - // - // if (!str.startsWith("{" + digestType + "}")) - // return digest(str); - // else - // return str; - // } - - // protected String digest(String nonEncrypted) { - // try { - // MessageDigest md = MessageDigest.getInstance(digestType); - // byte[] dig = md.digest(nonEncrypted.getBytes()); - // return "{" + digestType + "}" - // + new String(Base64.encodeBase64(dig)); - // } catch (NoSuchAlgorithmException e) { - // throw new RuntimeException( - // "Unexpected exception while digesting password"); - // } - // } - - public void setUserDeserializer(Deserializer userDeserializer) { - this.userDeserializer = userDeserializer; - } - - public void setSecurityService(ArgeoSecurityService securityService) { - this.securityService = securityService; - } +// @RequestMapping("/getRolesList.*") +// @ModelAttribute("roles") +// public Set getEditableRolesList() { +// return securityService.listEditableRoles(); +// } +// +// @RequestMapping("/createRole.*") +// public ServerAnswer createRole(@RequestParam("role") String role) { +// securityService.newRole(role); +// return ServerAnswer.ok("Role " + role + " created"); +// } +// +// @RequestMapping("/deleteRole.*") +// public ServerAnswer deleteRole(@RequestParam("role") String role) { +// securityService.deleteRole(role); +// return ServerAnswer.ok("Role " + role + " deleted"); +// } +// +// @RequestMapping("/updateUserPassword.*") +// public ServerAnswer updateUserPassword( +// @RequestParam("username") String username, +// @RequestParam("password") String password) { +// securityService.updateUserPassword(username, password); +// return ServerAnswer.ok("Password updated for user " + username); +// } +// +// @RequestMapping("/updatePassword.*") +// public ServerAnswer updatePassword( +// @RequestParam("oldPassword") String oldPassword, +// @RequestParam("password") String password) { +// securityService.updateCurrentUserPassword(oldPassword, password); +// return ServerAnswer.ok("Password updated"); +// } +// +// public void setUserDeserializer(Deserializer userDeserializer) { +// this.userDeserializer = userDeserializer; +// } +// +// public void setSecurityService(ArgeoSecurityService securityService) { +// this.securityService = securityService; +// } } diff --git a/security/runtime/pom.xml b/security/runtime/pom.xml index 1374dde72..ccb425d09 100644 --- a/security/runtime/pom.xml +++ b/security/runtime/pom.xml @@ -16,6 +16,7 @@ org.argeo.security.ldap org.argeo.security.activemq org.argeo.security.jackrabbit + org.argeo.security.mvc diff --git a/server/dep/org.argeo.server.dep.jackrabbit.server/pom.xml b/server/dep/org.argeo.server.dep.jackrabbit.server/pom.xml index 150e97550..9a6ea84b8 100644 --- a/server/dep/org.argeo.server.dep.jackrabbit.server/pom.xml +++ b/server/dep/org.argeo.server.dep.jackrabbit.server/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 org.argeo.commons.server @@ -11,106 +12,48 @@ Commons Jackrabbit Dependencies - org.argeo.dep.osgi - org.argeo.dep.osgi.jackrabbit - - - org.argeo.commons.server - org.argeo.server.tika.jackrabbit - ${version.argeo-commons} - - - org.argeo.commons.server - org.argeo.server.ext.jackrabbit - ${version.argeo-commons} - - - org.apache.xalan - com.springsource.org.apache.xalan - - - - - org.argeo.dep.osgi - org.argeo.dep.osgi.jcr - - - org.apache.lucene - com.springsource.org.apache.lucene - - - org.argeo.commons.basic - org.argeo.basic.dep.log4j - 0.3.2-SNAPSHOT + org.argeo.commons.osgi + org.argeo.osgi.dep.jackrabbit pom + 0.3.2-SNAPSHOT - - - org.apache.commons - com.springsource.org.apache.commons.collections - - - org.apache.commons - com.springsource.org.apache.commons.io - - - org.apache.commons - com.springsource.org.apache.commons.httpclient - + - org.apache.commons - com.springsource.org.apache.commons.fileupload - - - org.apache.commons - com.springsource.org.apache.commons.compress - - - org.apache.commons - com.springsource.org.apache.commons.pool - - - org.apache.commons - com.springsource.org.apache.commons.dbcp + org.argeo.dep.osgi + org.argeo.dep.osgi.bouncycastle.jdk15 - - - edu.oswego.cs.concurrent - com.springsource.edu.oswego.cs.dl.util.concurrent + org.apache.xmlbeans + com.springsource.org.apache.xmlbeans - - - org.springframework - org.springframework.web.servlet + org.apache.xmlcommons + com.springsource.org.apache.xmlcommons - javax.servlet - com.springsource.javax.servlet + org.argeo.dep.osgi + org.argeo.dep.osgi.pdfbox - - org.argeo.dep.osgi - org.argeo.dep.osgi.tika + org.argeo.dep.osgi.poi - org.argeo.dep.osgi - org.argeo.dep.osgi.pdfbox + com.sun.syndication + com.springsource.com.sun.syndication - org.argeo.dep.osgi - org.argeo.dep.osgi.poi + net.sourceforge.nekohtml + com.springsource.org.cyberneko.html org.argeo.dep.osgi org.argeo.dep.osgi.boilerpipe - org.argeo.dep.osgi - org.argeo.dep.osgi.bouncycastle.jdk15 + javax.mail + com.springsource.javax.mail org.argeo.dep.osgi @@ -124,58 +67,5 @@ org.argeo.dep.osgi org.argeo.dep.osgi.tagsoup - - - - - - net.sourceforge.nekohtml - com.springsource.org.cyberneko.html - - - javax.mail - com.springsource.javax.mail - - - org.apache.xmlbeans - com.springsource.org.apache.xmlbeans - - - org.dom4j - com.springsource.org.dom4j - - - org.jdom - com.springsource.org.jdom - - - com.sun.syndication - com.springsource.com.sun.syndication - - - org.objectweb.asm - com.springsource.org.objectweb.asm - - - org.jaxen - com.springsource.org.jaxen - - - org.xmlpull - com.springsource.org.xmlpull - - - org.argeo.commons.server - org.argeo.server.dep.javax - 0.3.2-SNAPSHOT - pom - - - org.apache.xmlcommons - com.springsource.org.apache.xmlcommons - - \ No newline at end of file diff --git a/server/modules/org.argeo.ext.jackrabbit.sybase/.project b/server/modules/org.argeo.ext.jackrabbit.sybase/.project new file mode 100644 index 000000000..e9939b5e9 --- /dev/null +++ b/server/modules/org.argeo.ext.jackrabbit.sybase/.project @@ -0,0 +1,22 @@ + + + org.argeo.server.ext.jackrabbit + + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + + diff --git a/server/modules/org.argeo.ext.jackrabbit.sybase/.settings/org.eclipse.pde.core.prefs b/server/modules/org.argeo.ext.jackrabbit.sybase/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 000000000..32c9e3fff --- /dev/null +++ b/server/modules/org.argeo.ext.jackrabbit.sybase/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,4 @@ +#Tue Jun 15 19:05:36 CEST 2010 +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/server/modules/org.argeo.ext.jackrabbit.sybase/META-INF/MANIFEST.MF b/server/modules/org.argeo.ext.jackrabbit.sybase/META-INF/MANIFEST.MF new file mode 100644 index 000000000..44777b599 --- /dev/null +++ b/server/modules/org.argeo.ext.jackrabbit.sybase/META-INF/MANIFEST.MF @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Jackrabbit +Bundle-SymbolicName: org.argeo.ext.jackrabbit.sybase +Bundle-Description: provides experimental support to Sybase in Jackrabbit +Bundle-Version: 0.3.2.SNAPSHOT +Fragment-Host: org.argeo.dep.osgi.jackrabbit diff --git a/server/modules/org.argeo.ext.jackrabbit.sybase/build.properties b/server/modules/org.argeo.ext.jackrabbit.sybase/build.properties new file mode 100644 index 000000000..5f22cdd44 --- /dev/null +++ b/server/modules/org.argeo.ext.jackrabbit.sybase/build.properties @@ -0,0 +1 @@ +bin.includes = META-INF/ diff --git a/server/modules/org.argeo.ext.jackrabbit.sybase/org/apache/jackrabbit/core/fs/db/sybase.ddl b/server/modules/org.argeo.ext.jackrabbit.sybase/org/apache/jackrabbit/core/fs/db/sybase.ddl new file mode 100644 index 000000000..fb8a0e8ca --- /dev/null +++ b/server/modules/org.argeo.ext.jackrabbit.sybase/org/apache/jackrabbit/core/fs/db/sybase.ddl @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +create table ${schemaObjectPrefix}FSENTRY (FSENTRY_PATH varchar(2048) not null, FSENTRY_NAME varchar(255) not null, FSENTRY_DATA image null, FSENTRY_LASTMOD decimal(19,0) not null, FSENTRY_LENGTH decimal(19,0) not null) +#create unique index ${schemaObjectPrefix}FSENTRY_IDX on ${schemaObjectPrefix}FSENTRY (FSENTRY_PATH, FSENTRY_NAME) diff --git a/server/modules/org.argeo.ext.jackrabbit.sybase/org/apache/jackrabbit/core/journal/sybase.ddl b/server/modules/org.argeo.ext.jackrabbit.sybase/org/apache/jackrabbit/core/journal/sybase.ddl new file mode 100644 index 000000000..d0f62428c --- /dev/null +++ b/server/modules/org.argeo.ext.jackrabbit.sybase/org/apache/jackrabbit/core/journal/sybase.ddl @@ -0,0 +1,22 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. + +create table ${schemaObjectPrefix}JOURNAL (REVISION_ID decimal(19,0) NOT NULL, JOURNAL_ID varchar(255), PRODUCER_ID varchar(255), REVISION_DATA IMAGE) +create unique index ${schemaObjectPrefix}JOURNAL_IDX on ${schemaObjectPrefix}JOURNAL (REVISION_ID) +create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID decimal(19,0) NOT NULL) +create unique index ${schemaObjectPrefix}GLOBAL_REVISION_IDX on ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID) + +# Inserting the one and only revision counter record now helps avoiding race conditions +insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0) diff --git a/server/modules/org.argeo.ext.jackrabbit.sybase/org/apache/jackrabbit/core/persistence/bundle/sybase.ddl b/server/modules/org.argeo.ext.jackrabbit.sybase/org/apache/jackrabbit/core/persistence/bundle/sybase.ddl new file mode 100644 index 000000000..47c6b71cf --- /dev/null +++ b/server/modules/org.argeo.ext.jackrabbit.sybase/org/apache/jackrabbit/core/persistence/bundle/sybase.ddl @@ -0,0 +1,22 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +create table ${schemaObjectPrefix}BUNDLE (NODE_ID binary(16) not null, BUNDLE_DATA image not null) +create unique index ${schemaObjectPrefix}BUNDLE_IDX on ${schemaObjectPrefix}BUNDLE (NODE_ID) +create table ${schemaObjectPrefix}REFS (NODE_ID binary(16) not null, REFS_DATA image not null) +create unique index ${schemaObjectPrefix}REFS_IDX on ${schemaObjectPrefix}REFS (NODE_ID) +create table ${schemaObjectPrefix}BINVAL (BINVAL_ID varchar(64) not null, BINVAL_DATA image not null) +create unique index ${schemaObjectPrefix}BINVAL_IDX on ${schemaObjectPrefix}BINVAL (BINVAL_ID) +#create table ${schemaObjectPrefix}NAMES (ID INTEGER IDENTITY(1,1) PRIMARY KEY, NAME varchar(255) COLLATE Latin1_General_CS_AS not null) +create table ${schemaObjectPrefix}NAMES (ID INTEGER IDENTITY PRIMARY KEY, NAME varchar(255)) diff --git a/server/modules/org.argeo.ext.jackrabbit.sybase/org/apache/jackrabbit/core/persistence/db/sybase.ddl b/server/modules/org.argeo.ext.jackrabbit.sybase/org/apache/jackrabbit/core/persistence/db/sybase.ddl new file mode 100644 index 000000000..2bde3231e --- /dev/null +++ b/server/modules/org.argeo.ext.jackrabbit.sybase/org/apache/jackrabbit/core/persistence/db/sybase.ddl @@ -0,0 +1,22 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +create table ${schemaObjectPrefix}NODE (NODE_ID char(36) not null, NODE_DATA image not null) +create unique index ${schemaObjectPrefix}NODE_IDX on ${schemaObjectPrefix}NODE (NODE_ID) +create table ${schemaObjectPrefix}PROP (PROP_ID varchar(1024) not null, PROP_DATA image not null) +create unique index ${schemaObjectPrefix}PROP_IDX on ${schemaObjectPrefix}PROP (PROP_ID) +create table ${schemaObjectPrefix}REFS (NODE_ID char(36) not null, REFS_DATA image not null) +create unique index ${schemaObjectPrefix}REFS_IDX on ${schemaObjectPrefix}REFS (NODE_ID) +create table ${schemaObjectPrefix}BINVAL (BINVAL_ID varchar(1024) not null, BINVAL_DATA image not null) +create unique index ${schemaObjectPrefix}BINVAL_IDX on ${schemaObjectPrefix}BINVAL (BINVAL_ID) diff --git a/server/modules/org.argeo.jackrabbit.webapp/META-INF/MANIFEST.MF b/server/modules/org.argeo.jackrabbit.webapp/META-INF/MANIFEST.MF index 47f864957..78fe43c74 100644 --- a/server/modules/org.argeo.jackrabbit.webapp/META-INF/MANIFEST.MF +++ b/server/modules/org.argeo.jackrabbit.webapp/META-INF/MANIFEST.MF @@ -14,7 +14,6 @@ Import-Package: javax.jcr, org.argeo.jackrabbit.remote, org.argeo.jcr, org.argeo.jcr.mvc, - org.argeo.server.json, org.argeo.server.mvc, org.springframework.aop;version="2.5.6.SEC01", org.springframework.aop.framework;version="2.5.6.SEC01", diff --git a/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/jcr-manager-servlet.xml b/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/jcr-manager-servlet.xml index 78670a61a..e2879ec30 100644 --- a/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/jcr-manager-servlet.xml +++ b/server/modules/org.argeo.jackrabbit.webapp/WEB-INF/jcr-manager-servlet.xml @@ -7,27 +7,27 @@ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> - + - - + + - - - + + + - - + + - + - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/server/modules/org.argeo.node.repo.jackrabbit/noderepo.properties b/server/modules/org.argeo.node.repo.jackrabbit/noderepo.properties index 8f2186127..d817e1454 100644 --- a/server/modules/org.argeo.node.repo.jackrabbit/noderepo.properties +++ b/server/modules/org.argeo.node.repo.jackrabbit/noderepo.properties @@ -2,11 +2,11 @@ argeo.node.repo.workspace=dev # Repository base directory -argeo.node.repo.home=${user.home}/.argeo/noderepo +argeo.node.repo.home=${osgi.instance.area}/org/argeo/jackrabbit/node/repo ## H2 Embedded (DEFAULT) argeo.node.repo.configuration=osgibundle:repository-h2.xml -argeo.node.repo.dburl=jdbc:h2:file:~/.argeo/h2/noderepo_db +argeo.node.repo.dburl=jdbc:h2:${osgi.instance.area}/org/argeo/jackrabbit/node/h2 argeo.node.repo.dbuser=sa argeo.node.repo.dbpassword= diff --git a/server/modules/org.argeo.server.ext.jackrabbit/.project b/server/modules/org.argeo.server.ext.jackrabbit/.project deleted file mode 100644 index e9939b5e9..000000000 --- a/server/modules/org.argeo.server.ext.jackrabbit/.project +++ /dev/null @@ -1,22 +0,0 @@ - - - org.argeo.server.ext.jackrabbit - - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - - org.eclipse.pde.PluginNature - - diff --git a/server/modules/org.argeo.server.ext.jackrabbit/.settings/org.eclipse.pde.core.prefs b/server/modules/org.argeo.server.ext.jackrabbit/.settings/org.eclipse.pde.core.prefs deleted file mode 100644 index 32c9e3fff..000000000 --- a/server/modules/org.argeo.server.ext.jackrabbit/.settings/org.eclipse.pde.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -#Tue Jun 15 19:05:36 CEST 2010 -eclipse.preferences.version=1 -pluginProject.extensions=false -resolve.requirebundle=false diff --git a/server/modules/org.argeo.server.ext.jackrabbit/META-INF/MANIFEST.MF b/server/modules/org.argeo.server.ext.jackrabbit/META-INF/MANIFEST.MF deleted file mode 100644 index 476f4b6c2..000000000 --- a/server/modules/org.argeo.server.ext.jackrabbit/META-INF/MANIFEST.MF +++ /dev/null @@ -1,7 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: Jackrabbit -Bundle-SymbolicName: org.argeo.server.ext.jackrabbit -Bundle-Description: provides additional DLLs and imports to Jackrabbit -Bundle-Version: 0.3.2.SNAPSHOT -Fragment-Host: org.argeo.dep.osgi.jackrabbit diff --git a/server/modules/org.argeo.server.ext.jackrabbit/build.properties b/server/modules/org.argeo.server.ext.jackrabbit/build.properties deleted file mode 100644 index 5f22cdd44..000000000 --- a/server/modules/org.argeo.server.ext.jackrabbit/build.properties +++ /dev/null @@ -1 +0,0 @@ -bin.includes = META-INF/ diff --git a/server/modules/org.argeo.server.ext.jackrabbit/org/apache/jackrabbit/core/fs/db/sybase.ddl b/server/modules/org.argeo.server.ext.jackrabbit/org/apache/jackrabbit/core/fs/db/sybase.ddl deleted file mode 100644 index fb8a0e8ca..000000000 --- a/server/modules/org.argeo.server.ext.jackrabbit/org/apache/jackrabbit/core/fs/db/sybase.ddl +++ /dev/null @@ -1,16 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. -create table ${schemaObjectPrefix}FSENTRY (FSENTRY_PATH varchar(2048) not null, FSENTRY_NAME varchar(255) not null, FSENTRY_DATA image null, FSENTRY_LASTMOD decimal(19,0) not null, FSENTRY_LENGTH decimal(19,0) not null) -#create unique index ${schemaObjectPrefix}FSENTRY_IDX on ${schemaObjectPrefix}FSENTRY (FSENTRY_PATH, FSENTRY_NAME) diff --git a/server/modules/org.argeo.server.ext.jackrabbit/org/apache/jackrabbit/core/journal/sybase.ddl b/server/modules/org.argeo.server.ext.jackrabbit/org/apache/jackrabbit/core/journal/sybase.ddl deleted file mode 100644 index d0f62428c..000000000 --- a/server/modules/org.argeo.server.ext.jackrabbit/org/apache/jackrabbit/core/journal/sybase.ddl +++ /dev/null @@ -1,22 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. - -create table ${schemaObjectPrefix}JOURNAL (REVISION_ID decimal(19,0) NOT NULL, JOURNAL_ID varchar(255), PRODUCER_ID varchar(255), REVISION_DATA IMAGE) -create unique index ${schemaObjectPrefix}JOURNAL_IDX on ${schemaObjectPrefix}JOURNAL (REVISION_ID) -create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID decimal(19,0) NOT NULL) -create unique index ${schemaObjectPrefix}GLOBAL_REVISION_IDX on ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID) - -# Inserting the one and only revision counter record now helps avoiding race conditions -insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0) diff --git a/server/modules/org.argeo.server.ext.jackrabbit/org/apache/jackrabbit/core/persistence/bundle/sybase.ddl b/server/modules/org.argeo.server.ext.jackrabbit/org/apache/jackrabbit/core/persistence/bundle/sybase.ddl deleted file mode 100644 index 47c6b71cf..000000000 --- a/server/modules/org.argeo.server.ext.jackrabbit/org/apache/jackrabbit/core/persistence/bundle/sybase.ddl +++ /dev/null @@ -1,22 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. -create table ${schemaObjectPrefix}BUNDLE (NODE_ID binary(16) not null, BUNDLE_DATA image not null) -create unique index ${schemaObjectPrefix}BUNDLE_IDX on ${schemaObjectPrefix}BUNDLE (NODE_ID) -create table ${schemaObjectPrefix}REFS (NODE_ID binary(16) not null, REFS_DATA image not null) -create unique index ${schemaObjectPrefix}REFS_IDX on ${schemaObjectPrefix}REFS (NODE_ID) -create table ${schemaObjectPrefix}BINVAL (BINVAL_ID varchar(64) not null, BINVAL_DATA image not null) -create unique index ${schemaObjectPrefix}BINVAL_IDX on ${schemaObjectPrefix}BINVAL (BINVAL_ID) -#create table ${schemaObjectPrefix}NAMES (ID INTEGER IDENTITY(1,1) PRIMARY KEY, NAME varchar(255) COLLATE Latin1_General_CS_AS not null) -create table ${schemaObjectPrefix}NAMES (ID INTEGER IDENTITY PRIMARY KEY, NAME varchar(255)) diff --git a/server/modules/org.argeo.server.ext.jackrabbit/org/apache/jackrabbit/core/persistence/db/sybase.ddl b/server/modules/org.argeo.server.ext.jackrabbit/org/apache/jackrabbit/core/persistence/db/sybase.ddl deleted file mode 100644 index 2bde3231e..000000000 --- a/server/modules/org.argeo.server.ext.jackrabbit/org/apache/jackrabbit/core/persistence/db/sybase.ddl +++ /dev/null @@ -1,22 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You 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. -create table ${schemaObjectPrefix}NODE (NODE_ID char(36) not null, NODE_DATA image not null) -create unique index ${schemaObjectPrefix}NODE_IDX on ${schemaObjectPrefix}NODE (NODE_ID) -create table ${schemaObjectPrefix}PROP (PROP_ID varchar(1024) not null, PROP_DATA image not null) -create unique index ${schemaObjectPrefix}PROP_IDX on ${schemaObjectPrefix}PROP (PROP_ID) -create table ${schemaObjectPrefix}REFS (NODE_ID char(36) not null, REFS_DATA image not null) -create unique index ${schemaObjectPrefix}REFS_IDX on ${schemaObjectPrefix}REFS (NODE_ID) -create table ${schemaObjectPrefix}BINVAL (BINVAL_ID varchar(1024) not null, BINVAL_DATA image not null) -create unique index ${schemaObjectPrefix}BINVAL_IDX on ${schemaObjectPrefix}BINVAL (BINVAL_ID) diff --git a/server/modules/org.argeo.server.tika.jackrabbit/.project b/server/modules/org.argeo.server.tika.jackrabbit/.project deleted file mode 100644 index 315771fe3..000000000 --- a/server/modules/org.argeo.server.tika.jackrabbit/.project +++ /dev/null @@ -1,22 +0,0 @@ - - - org.argeo.server.tika.jackrabbit - - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - - org.eclipse.pde.PluginNature - - diff --git a/server/modules/org.argeo.server.tika.jackrabbit/.settings/org.eclipse.pde.core.prefs b/server/modules/org.argeo.server.tika.jackrabbit/.settings/org.eclipse.pde.core.prefs deleted file mode 100644 index c8bc6bc2e..000000000 --- a/server/modules/org.argeo.server.tika.jackrabbit/.settings/org.eclipse.pde.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -#Mon Jan 10 13:35:52 CET 2011 -eclipse.preferences.version=1 -pluginProject.extensions=false -resolve.requirebundle=false diff --git a/server/modules/org.argeo.server.tika.jackrabbit/META-INF/MANIFEST.MF b/server/modules/org.argeo.server.tika.jackrabbit/META-INF/MANIFEST.MF deleted file mode 100644 index ccdf8b216..000000000 --- a/server/modules/org.argeo.server.tika.jackrabbit/META-INF/MANIFEST.MF +++ /dev/null @@ -1,7 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: Tika Jackrabbit extension -Bundle-SymbolicName: org.argeo.server.tika.jackrabbit -Bundle-Version: 0.3.2.SNAPSHOT -Fragment-Host: org.argeo.dep.osgi.tika -Import-Package: org.apache.jackrabbit.core.query.pdf diff --git a/server/modules/org.argeo.server.tika.jackrabbit/build.properties b/server/modules/org.argeo.server.tika.jackrabbit/build.properties deleted file mode 100644 index 5f22cdd44..000000000 --- a/server/modules/org.argeo.server.tika.jackrabbit/build.properties +++ /dev/null @@ -1 +0,0 @@ -bin.includes = META-INF/ diff --git a/server/runtime/org.argeo.server.jackrabbit/build.properties b/server/runtime/org.argeo.server.jackrabbit/build.properties index cd05956ed..909ad1915 100644 --- a/server/runtime/org.argeo.server.jackrabbit/build.properties +++ b/server/runtime/org.argeo.server.jackrabbit/build.properties @@ -3,7 +3,7 @@ additional.bundles = com.springsource.slf4j.api,\ com.springsource.org.apache.log4j,\ com.springsource.org.apache.commons.collections,\ com.springsource.edu.oswego.cs.dl.util.concurrent,\ - com.springsource.org.apache.derby,\ + com.springsource.org.h2,\ com.springsource.org.apache.lucene,\ org.springframework.context source.. = src/main/java/,\ diff --git a/server/runtime/org.argeo.server.jackrabbit/pom.xml b/server/runtime/org.argeo.server.jackrabbit/pom.xml index 9a28d58cd..82fbb25c8 100644 --- a/server/runtime/org.argeo.server.jackrabbit/pom.xml +++ b/server/runtime/org.argeo.server.jackrabbit/pom.xml @@ -50,7 +50,6 @@ org.argeo.basic.nodeps 0.3.2-SNAPSHOT - org.argeo.commons.server org.argeo.server.core @@ -64,20 +63,10 @@ - org.argeo.commons.server - org.argeo.server.dep.jackrabbit.server - 0.3.2-SNAPSHOT + org.argeo.commons.osgi + org.argeo.osgi.dep.jackrabbit pom - - - javax.servlet - com.springsource.javax.servlet - - - - - org.apache.commons - com.springsource.org.apache.commons.io + 0.3.2-SNAPSHOT @@ -85,28 +74,15 @@ org.springframework org.springframework.beans - org.springframework org.springframework.web.servlet - org.springframework.ws org.springframework.xml - - - org.slf4j - com.springsource.slf4j.org.apache.commons.logging - - - - org.apache.commons - com.springsource.org.apache.commons.fileupload - - org.argeo.commons.basic diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java index 942313f8a..eb090514f 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/java/org/argeo/jackrabbit/JackrabbitContainer.java @@ -18,6 +18,7 @@ package org.argeo.jackrabbit; import java.io.ByteArrayInputStream; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; @@ -55,6 +56,7 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ResourceLoaderAware; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; +import org.springframework.util.SystemPropertyUtils; import org.xml.sax.InputSource; /** @@ -111,16 +113,9 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean, } RepositoryConfig config; + Properties vars = getConfigurationProperties(); InputStream in = configuration.getInputStream(); - InputStream propsIn = null; try { - Properties vars = new Properties(); - if (variables != null) { - propsIn = variables.getInputStream(); - vars.load(propsIn); - } - // override with system properties - vars.putAll(System.getProperties()); vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, homeDirectory.getCanonicalPath()); config = RepositoryConfig.create(new InputSource(in), vars); @@ -128,7 +123,6 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean, throw new RuntimeException("Cannot read configuration", e); } finally { IOUtils.closeQuietly(in); - IOUtils.closeQuietly(propsIn); } if (inMemory) @@ -143,6 +137,32 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean, + homeDirectory + " with config " + configuration); } + protected Properties getConfigurationProperties() { + InputStream propsIn = null; + Properties vars; + try { + vars = new Properties(); + if (variables != null) { + propsIn = variables.getInputStream(); + vars.load(propsIn); + } + // resolve system properties + for (Object key : vars.keySet()) { + // TODO: implement a smarter mechanism to resolve nested ${} + String newValue = SystemPropertyUtils.resolvePlaceholders(vars + .getProperty(key.toString())); + vars.put(key, newValue); + } + // override with system properties + vars.putAll(System.getProperties()); + } catch (IOException e) { + throw new ArgeoException("Cannot read configuration properties", e); + } finally { + IOUtils.closeQuietly(propsIn); + } + return vars; + } + /** * Import declared node type definitions, trying to update them if they have * changed. In case of failures an error will be logged but no exception @@ -192,7 +212,7 @@ public class JackrabbitContainer implements InitializingBean, DisposableBean, else action.run(); } - + public void destroy() throws Exception { if (repository != null) { if (repository instanceof JackrabbitRepository) diff --git a/server/runtime/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-inMemory.xml b/server/runtime/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-inMemory.xml index 289a408c5..348dc288b 100644 --- a/server/runtime/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-inMemory.xml +++ b/server/runtime/org.argeo.server.jackrabbit/src/main/resources/org/argeo/jackrabbit/repository-inMemory.xml @@ -1,155 +1,81 @@ - - - + "http://jackrabbit.apache.org/dtd/repository-2.0.dtd"> - - - - - - - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - + + + + + + + + + + - + - + defaultWorkspace="dev" /> - - - + + + + - - - - - + class="org.apache.jackrabbit.core.persistence.pool.H2PersistenceManager"> + + - - - - + - - - + + + + - - - - - - + class="org.apache.jackrabbit.core.persistence.pool.H2PersistenceManager"> + + - + - + + + + + + + + + + + \ No newline at end of file diff --git a/server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/JcrManagerController.java b/server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/JcrManagerController.java index 55aecae95..b42bd7a75 100644 --- a/server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/JcrManagerController.java +++ b/server/runtime/org.argeo.server.jcr.mvc/src/main/java/org/argeo/jcr/mvc/JcrManagerController.java @@ -90,7 +90,7 @@ public class JcrManagerController implements MvcConstants, JcrMvcConstants { // pathInfo.indexOf('/')); if (log.isDebugEnabled()) log.debug("Upload to " + path); - resourceAdapter.update(path.toString(), res); + resourceAdapter.update(path.toString(), res.getInputStream()); return ServerAnswer.ok("File " + path + " imported"); } diff --git a/server/runtime/org.argeo.server.jcr/build.properties b/server/runtime/org.argeo.server.jcr/build.properties index a4f357883..b0df02563 100644 --- a/server/runtime/org.argeo.server.jcr/build.properties +++ b/server/runtime/org.argeo.server.jcr/build.properties @@ -11,11 +11,11 @@ additional.bundles = com.springsource.slf4j.api,\ com.springsource.org.apache.log4j,\ com.springsource.org.apache.commons.collections,\ com.springsource.edu.oswego.cs.dl.util.concurrent,\ - com.springsource.org.apache.derby,\ com.springsource.org.apache.lucene,\ com.springsource.junit,\ com.springsource.org.apache.xml.serializer,\ com.springsource.org.apache.commons.dbcp,\ com.springsource.org.apache.commons.pool,\ - org.argeo.dep.osgi.jackrabbit + org.argeo.dep.osgi.jackrabbit,\ + com.springsource.org.h2 diff --git a/server/runtime/org.argeo.server.jcr/pom.xml b/server/runtime/org.argeo.server.jcr/pom.xml index 218e368b0..a08502486 100644 --- a/server/runtime/org.argeo.server.jcr/pom.xml +++ b/server/runtime/org.argeo.server.jcr/pom.xml @@ -1,4 +1,5 @@ - + 4.0.0 org.argeo.commons.server @@ -32,6 +33,9 @@ junit.framework;resolution:=optional, org.xml.sax;version="0.0.0", + org.springframework.core;resolution:=optional, + org.springframework.core.io;resolution:=optional, + org.springframework.*;resolution:=optional, * @@ -76,6 +80,7 @@ org.springframework org.springframework.beans + provided @@ -91,24 +96,20 @@ com.springsource.slf4j.org.apache.commons.logging + + org.junit com.springsource.junit true - - - org.argeo.commons.server - org.argeo.server.dep.jackrabbit.server + org.argeo.commons.osgi + org.argeo.osgi.dep.jackrabbit 0.3.2-SNAPSHOT pom test - - org.apache.derby - com.springsource.org.apache.derby - org.argeo.commons.basic org.argeo.support.junit diff --git a/server/runtime/org.argeo.server.jcr/repository.xml b/server/runtime/org.argeo.server.jcr/repository.xml deleted file mode 100644 index 666919d28..000000000 --- a/server/runtime/org.argeo.server.jcr/repository.xml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/BeanNodeMapper.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/BeanNodeMapper.java deleted file mode 100644 index 634069996..000000000 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/BeanNodeMapper.java +++ /dev/null @@ -1,644 +0,0 @@ -/* - * Copyright (C) 2010 Mathieu Baudier - * - * 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 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.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.springframework.beans.BeanWrapper; -import org.springframework.beans.BeanWrapperImpl; - -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, - 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) - return valueFactory.createValue((InputStream) value); - 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.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.getNodeByUUID(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; - } -} diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrResourceAdapter.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrResourceAdapter.java index 583995057..6c7c06b84 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrResourceAdapter.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrResourceAdapter.java @@ -16,16 +16,17 @@ package org.argeo.jcr; -import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Calendar; import java.util.List; +import javax.jcr.Binary; import javax.jcr.Node; import javax.jcr.Property; import javax.jcr.RepositoryException; import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; import javax.jcr.version.Version; import javax.jcr.version.VersionHistory; import javax.jcr.version.VersionIterator; @@ -33,7 +34,6 @@ import javax.jcr.version.VersionIterator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; -import org.springframework.core.io.Resource; /** * Bridge Spring resources and JCR folder / files semantics (nt:folder / @@ -57,15 +57,8 @@ public class JcrResourceAdapter { } public void mkdirs(String path) { - JcrUtils.mkdirs(session(), path, "nt:folder", "nt:folder", versioning); - } - - public void create(String path, Resource file, String mimeType) { - try { - create(path, file.getInputStream(), mimeType); - } catch (IOException e) { - throw new ArgeoException("Cannot read " + file, e); - } + JcrUtils.mkdirs(session(), path, NodeType.NT_FOLDER, + NodeType.NT_FOLDER, versioning); } public void create(String path, InputStream in, String mimeType) { @@ -86,14 +79,17 @@ public class JcrResourceAdapter { Node folderNode = (Node) session().getItem(parentPath); Node fileNode = folderNode.addNode(fileName, "nt:file"); - Node contentNode = fileNode.addNode("jcr:content", "nt:resource"); + Node contentNode = fileNode.addNode(Property.JCR_CONTENT, + "nt:resource"); if (mimeType != null) - contentNode.setProperty("jcr:mimeType", mimeType); - contentNode.setProperty("jcr:encoding", defaultEncoding); - contentNode.setProperty("jcr:data", in); + contentNode.setProperty(Property.JCR_MIMETYPE, mimeType); + contentNode.setProperty(Property.JCR_ENCODING, defaultEncoding); + Binary binary = session().getValueFactory().createBinary(in); + contentNode.setProperty(Property.JCR_DATA, binary); + JcrUtils.closeQuietly(binary); Calendar lastModified = Calendar.getInstance(); // lastModified.setTimeInMillis(file.lastModified()); - contentNode.setProperty("jcr:lastModified", lastModified); + contentNode.setProperty(Property.JCR_LAST_MODIFIED, lastModified); // resNode.addMixin("mix:referenceable"); if (versioning) @@ -102,7 +98,8 @@ public class JcrResourceAdapter { session().save(); if (versioning) - fileNode.checkin(); + session().getWorkspace().getVersionManager() + .checkin(fileNode.getPath()); if (log.isDebugEnabled()) log.debug("Created " + path); @@ -112,14 +109,6 @@ public class JcrResourceAdapter { } - public void update(String path, Resource file) { - try { - update(path, file.getInputStream()); - } catch (IOException e) { - throw new ArgeoException("Cannot read " + file, e); - } - } - public void update(String path, InputStream in) { try { @@ -134,17 +123,21 @@ public class JcrResourceAdapter { } Node fileNode = (Node) session().getItem(path); - Node contentNode = fileNode.getNode("jcr:content"); + Node contentNode = fileNode.getNode(Property.JCR_CONTENT); if (versioning) - fileNode.checkout(); - contentNode.setProperty("jcr:data", in); + session().getWorkspace().getVersionManager() + .checkout(fileNode.getPath()); + Binary binary = session().getValueFactory().createBinary(in); + contentNode.setProperty(Property.JCR_DATA, binary); + JcrUtils.closeQuietly(binary); Calendar lastModified = Calendar.getInstance(); // lastModified.setTimeInMillis(file.lastModified()); - contentNode.setProperty("jcr:lastModified", lastModified); + contentNode.setProperty(Property.JCR_LAST_MODIFIED, lastModified); session().save(); if (versioning) - fileNode.checkin(); + session().getWorkspace().getVersionManager() + .checkin(fileNode.getPath()); if (log.isDebugEnabled()) log.debug("Updated " + path); @@ -160,7 +153,8 @@ public class JcrResourceAdapter { try { List versions = new ArrayList(); Node fileNode = (Node) session().getItem(path); - VersionHistory history = fileNode.getVersionHistory(); + VersionHistory history = session().getWorkspace() + .getVersionManager().getVersionHistory(fileNode.getPath()); for (VersionIterator it = history.getAllVersions(); it.hasNext();) { Version version = (Version) it.next(); versions.add(version.getCreated()); @@ -177,9 +171,10 @@ public class JcrResourceAdapter { public InputStream retrieve(String path) { try { - Node node = (Node) session().getItem(path + "/jcr:content"); - Property property = node.getProperty("jcr:data"); - return property.getStream(); + Node node = (Node) session().getItem( + path + "/" + Property.JCR_CONTENT); + Property property = node.getProperty(Property.JCR_DATA); + return property.getBinary().getStream(); } catch (Exception e) { throw new ArgeoException("Cannot retrieve " + path, e); } @@ -191,7 +186,8 @@ public class JcrResourceAdapter { try { Node fileNode = (Node) session().getItem(path); - VersionHistory history = fileNode.getVersionHistory(); + VersionHistory history = session().getWorkspace() + .getVersionManager().getVersionHistory(fileNode.getPath()); int count = 0; Version version = null; for (VersionIterator it = history.getAllVersions(); it.hasNext();) { @@ -217,8 +213,8 @@ public class JcrResourceAdapter { protected InputStream fromVersion(Version version) throws RepositoryException { Node frozenNode = version.getNode("jcr:frozenNode"); - InputStream in = frozenNode.getNode("jcr:content") - .getProperty("jcr:data").getStream(); + InputStream in = frozenNode.getNode(Property.JCR_CONTENT) + .getProperty(Property.JCR_DATA).getBinary().getStream(); return in; } diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUrlStreamHandler.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUrlStreamHandler.java index 1f803bf80..82a65e7f1 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUrlStreamHandler.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/JcrUrlStreamHandler.java @@ -6,7 +6,6 @@ import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; -import javax.jcr.Binary; import javax.jcr.Item; import javax.jcr.Node; import javax.jcr.Property; @@ -47,7 +46,7 @@ public class JcrUrlStreamHandler extends URLStreamHandler { } else { Property property = (Property) item; if(property.getType()==PropertyType.BINARY){ - Binary binary = property.getBinary(); + //Binary binary = property.getBinary(); } } diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java index 1c33a43de..d548b6edd 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/ThreadBoundJcrSessionFactory.java @@ -35,13 +35,9 @@ import javax.jcr.SimpleCredentials; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; /** Proxy JCR sessions and attach them to calling threads. */ -public class ThreadBoundJcrSessionFactory implements FactoryBean, - InitializingBean, DisposableBean { +public class ThreadBoundJcrSessionFactory { private final static Log log = LogFactory .getLog(ThreadBoundJcrSessionFactory.class); @@ -126,12 +122,12 @@ public class ThreadBoundJcrSessionFactory implements FactoryBean, return proxiedSession; } - public void afterPropertiesSet() throws Exception { + public void init() throws Exception { monitoringThread = new MonitoringThread(); monitoringThread.start(); } - public synchronized void destroy() throws Exception { + public synchronized void dispose() throws Exception { if (activeSessions.size() == 0) return; diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/CaManager.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/CaManager.java index ffa434fc1..be6687ce6 100644 --- a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/CaManager.java +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/security/CaManager.java @@ -1,8 +1,7 @@ package org.argeo.jcr.security; -import javax.jcr.Session; public class CaManager { -private Session session; + // private Session session; } diff --git a/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/spring/BeanNodeMapper.java b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/spring/BeanNodeMapper.java new file mode 100644 index 000000000..8f866ba3b --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/main/java/org/argeo/jcr/spring/BeanNodeMapper.java @@ -0,0 +1,650 @@ +/* + * Copyright (C) 2010 Mathieu Baudier + * + * 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; + +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; + } +} diff --git a/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/MapperTest.java b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/MapperTest.java index 121d72298..8f276991d 100644 --- a/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/MapperTest.java +++ b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/jcr/MapperTest.java @@ -22,6 +22,7 @@ import javax.jcr.Node; import javax.jcr.Repository; import org.apache.jackrabbit.core.TransientRepository; +import org.argeo.jcr.spring.BeanNodeMapper; import org.argeo.jcr.unit.AbstractJcrTestCase; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; @@ -51,7 +52,7 @@ public class MapperTest extends AbstractJcrTestCase { protected File getRepositoryFile() throws Exception { Resource res = new ClassPathResource( - "org/argeo/server/jcr/repository.xml"); + "org/argeo/server/jcr/repository-h2.xml"); return res.getFile(); } diff --git a/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/server/jcr/JcrResourceAdapterTest.java b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/server/jcr/JcrResourceAdapterTest.java index 51e3af2d8..32bfa9fc2 100644 --- a/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/server/jcr/JcrResourceAdapterTest.java +++ b/server/runtime/org.argeo.server.jcr/src/test/java/org/argeo/server/jcr/JcrResourceAdapterTest.java @@ -47,7 +47,7 @@ public class JcrResourceAdapterTest extends AbstractJcrTestCase { jra.mkdirs(basePath); Resource res = new ClassPathResource("org/argeo/server/jcr/dummy00.xls"); String filePath = basePath + "/dummy.xml"; - jra.create(filePath, res, "application/vnd.ms-excel"); + jra.create(filePath, res.getInputStream(), "application/vnd.ms-excel"); InputStream in = jra.retrieve(filePath); assertTrue(IOUtils.contentEquals(res.getInputStream(), in)); } @@ -58,13 +58,13 @@ public class JcrResourceAdapterTest extends AbstractJcrTestCase { String filePath = basePath + "/dummy.xml"; Resource res00 = new ClassPathResource( "org/argeo/server/jcr/dummy00.xls"); - jra.create(filePath, res00, "application/vnd.ms-excel"); + jra.create(filePath, res00.getInputStream(), "application/vnd.ms-excel"); Resource res01 = new ClassPathResource( "org/argeo/server/jcr/dummy01.xls"); - jra.update(filePath, res01); + jra.update(filePath, res01.getInputStream()); Resource res02 = new ClassPathResource( "org/argeo/server/jcr/dummy02.xls"); - jra.update(filePath, res02); + jra.update(filePath, res02.getInputStream()); List versions = jra.listVersions(filePath); log.debug("Versions of " + filePath); @@ -85,7 +85,7 @@ public class JcrResourceAdapterTest extends AbstractJcrTestCase { assertTrue(IOUtils.contentEquals(res02.getInputStream(), in)); Resource res03 = new ClassPathResource( "org/argeo/server/jcr/dummy03.xls"); - jra.update(filePath, res03); + jra.update(filePath, res03.getInputStream()); in = jra.retrieve(filePath, 1); assertTrue(IOUtils.contentEquals(res01.getInputStream(), in)); } @@ -106,7 +106,7 @@ public class JcrResourceAdapterTest extends AbstractJcrTestCase { protected File getRepositoryFile() throws Exception { Resource res = new ClassPathResource( - "org/argeo/server/jcr/repository.xml"); + "org/argeo/server/jcr/repository-h2.xml"); return res.getFile(); } diff --git a/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/repository-h2.xml b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/repository-h2.xml new file mode 100644 index 000000000..348dc288b --- /dev/null +++ b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/repository-h2.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/repository.xml b/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/repository.xml deleted file mode 100644 index db6bfa742..000000000 --- a/server/runtime/org.argeo.server.jcr/src/test/resources/org/argeo/server/jcr/repository.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -