From: Mathieu Baudier Date: Tue, 10 Feb 2015 10:40:11 +0000 (+0000) Subject: Remove or merge bundles X-Git-Tag: argeo-commons-2.1.30~406 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=0a63088e055dcd5ff397ce4e98d008c62c84dc98;p=lgpl%2Fargeo-commons.git Remove or merge bundles Clean up POMs git-svn-id: https://svn.argeo.org/commons/trunk@7775 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/dep/org.argeo.dep.cms/pom.xml b/dep/org.argeo.dep.cms/pom.xml index ca9bde218..6bba46fd6 100644 --- a/dep/org.argeo.dep.cms/pom.xml +++ b/dep/org.argeo.dep.cms/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.argeo.commons @@ -8,33 +9,7 @@ .. org.argeo.dep.cms - Commons CMS Dependencies - - - - org.apache.felix - maven-bundle-plugin - - - default - - - - - org.argeo.maven.plugins - maven-argeo-osgi-plugin - - - generate-descriptors - - descriptors - - generate-resources - - - - - + Commons CMS Light org.argeo.commons @@ -93,10 +68,6 @@ - - org.argeo.tp.rap.platform - javax.xml - org.argeo.tp.rap.platform org.eclipse.rap.ui.workbench @@ -209,41 +180,16 @@ - - - - - - - - + + org.argeo.tp.apache.ant + org.apache.ant + + + org.argeo.tp.apache.ant + org.apache.ant.launch + - - - check-osgi - - - - org.argeo.maven.plugins - maven-argeo-osgi-plugin - - - check-osgi - test - - equinox - - - true - - - - - - - - \ No newline at end of file diff --git a/dep/org.argeo.security.dep.node.rap/pom.xml b/dep/org.argeo.security.dep.node.rap/pom.xml index 14bd5b919..002365fa7 100644 --- a/dep/org.argeo.security.dep.node.rap/pom.xml +++ b/dep/org.argeo.security.dep.node.rap/pom.xml @@ -7,35 +7,9 @@ .. org.argeo.security.dep.node.rap - Node Eclipse RAP - - - - org.apache.felix - maven-bundle-plugin - - - default - - - - - org.argeo.maven.plugins - maven-argeo-osgi-plugin - - - generate-descriptors - - descriptors - - generate-resources - - - - - + Commons CMS Full - + org.argeo.commons org.argeo.cms @@ -58,11 +32,6 @@ org.argeo.security.ui.admin 2.1.14-SNAPSHOT - - - - - @@ -70,12 +39,6 @@ org.argeo.security.dep.node 2.1.14-SNAPSHOT pom - - - - org.argeo.commons @@ -89,37 +52,5 @@ argeo-tp ${version.argeo-distribution} - - - - - - - check-osgi - - - - org.argeo.maven.plugins - maven-argeo-osgi-plugin - - - check-osgi - test - - equinox - - - true - - - - - - - - diff --git a/dep/org.argeo.security.dep.node/pom.xml b/dep/org.argeo.security.dep.node/pom.xml index 507bb9353..9c6440fd0 100644 --- a/dep/org.argeo.security.dep.node/pom.xml +++ b/dep/org.argeo.security.dep.node/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.argeo.commons @@ -8,33 +9,7 @@ .. org.argeo.security.dep.node - Node Backend - - - - org.apache.felix - maven-bundle-plugin - - - default - - - - - org.argeo.maven.plugins - maven-argeo-osgi-plugin - - - generate-descriptors - - descriptors - - generate-resources - - - - - + Commons Backend @@ -43,13 +18,6 @@ ${version.argeo-distribution} - - - - - - - org.argeo.commons @@ -64,10 +32,10 @@ 2.1.14-SNAPSHOT - + org.argeo.commons - org.argeo.server.jackrabbit + org.argeo.server.jcr 2.1.14-SNAPSHOT @@ -75,37 +43,5 @@ org.argeo.security.jackrabbit 2.1.14-SNAPSHOT - - - - - - - - - - check-osgi - - - - org.argeo.maven.plugins - maven-argeo-osgi-plugin - - - check-osgi - test - - equinox - - - true - - - - - - - - \ No newline at end of file diff --git a/dep/pom.xml b/dep/pom.xml index 5702442ab..200cf2ce6 100644 --- a/dep/pom.xml +++ b/dep/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.argeo.commons @@ -8,16 +9,62 @@ .. dep - Commons Base Dependencies + Commons Modular Distributions pom org.argeo.security.dep.node org.argeo.dep.cms org.argeo.security.dep.node.rap + + + + org.apache.felix + maven-bundle-plugin + + + default + + + + + org.argeo.maven.plugins + maven-argeo-osgi-plugin + + + generate-descriptors + + descriptors + + generate-resources + + + + + check-osgi + + + + org.argeo.maven.plugins + maven-argeo-osgi-plugin + + + check-osgi + test + + equinox + + + true + + + + + + org.argeo.commons diff --git a/dist/osgi-boot/pom.xml b/dist/osgi-boot/pom.xml index 06eefe9e3..9a81e9b1c 100644 --- a/dist/osgi-boot/pom.xml +++ b/dist/osgi-boot/pom.xml @@ -8,9 +8,9 @@ osgi-boot pom - Commons OSGi Boot Distribution + Commons Deployable OSGi Boot - 3.9.1.v20140110-1610 + 3.10.1.v20140909-1633 diff --git a/dist/pom.xml b/dist/pom.xml index adcc087df..da75c3bea 100644 --- a/dist/pom.xml +++ b/dist/pom.xml @@ -8,7 +8,7 @@ .. dist - Commons Distributions + Commons Deployable Distributions pom osgi-boot diff --git a/org.argeo.cms/bnd.bnd b/org.argeo.cms/bnd.bnd index 477223485..bdcfd61d0 100644 --- a/org.argeo.cms/bnd.bnd +++ b/org.argeo.cms/bnd.bnd @@ -8,9 +8,10 @@ javax.jcr.security,\ org.xml.sax;version="0.0.0",\ org.eclipse.swt.widgets;version="0.0.0",\ org.argeo.jcr,\ -org.h2;resolution:=optional,\ org.springframework.context,\ org.apache.jackrabbit.api,\ org.apache.jackrabbit.commons,\ org.eclipse.rap.rwt.osgi,\ +org.h2;resolution:=optional,\ +org.apache.commons.vfs2.*;resolution:=optional,\ * diff --git a/org.argeo.cms/pom.xml b/org.argeo.cms/pom.xml index b2a398d2a..660a263fc 100644 --- a/org.argeo.cms/pom.xml +++ b/org.argeo.cms/pom.xml @@ -8,7 +8,7 @@ .. org.argeo.cms - Commons Content Management System + Commons CMS jar @@ -16,58 +16,15 @@ org.argeo.server.jcr 2.1.14-SNAPSHOT - - org.argeo.commons - org.argeo.server.jackrabbit - 2.1.14-SNAPSHOT - - org.argeo.commons org.argeo.security.core 2.1.14-SNAPSHOT - - - - - - - org.argeo.commons org.argeo.eclipse.ui 2.1.14-SNAPSHOT - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/CmsApplication.java b/org.argeo.cms/src/org/argeo/cms/CmsApplication.java index af8fa1c99..7871ee086 100644 --- a/org.argeo.cms/src/org/argeo/cms/CmsApplication.java +++ b/org.argeo.cms/src/org/argeo/cms/CmsApplication.java @@ -23,6 +23,7 @@ import org.eclipse.rap.rwt.service.ResourceLoader; import org.osgi.framework.BundleContext; /** Configures an Argeo CMS RWT application. */ +@SuppressWarnings("deprecation") public class CmsApplication implements CmsConstants, ApplicationConfiguration, BundleContextAware { final static Log log = LogFactory.getLog(CmsApplication.class); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/AbstractAtomicBackup.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/AbstractAtomicBackup.java new file mode 100644 index 000000000..88fbb5a1c --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/AbstractAtomicBackup.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemManager; +import org.apache.commons.vfs2.FileSystemOptions; +import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder; +import org.argeo.ArgeoException; + +/** + * Simplify atomic backups implementation, especially by managing VFS. + */ +public abstract class AbstractAtomicBackup implements AtomicBackup { + private String name; + private String compression = "bz2"; + + protected abstract void writeBackup(FileObject targetFo); + + public AbstractAtomicBackup() { + } + + public AbstractAtomicBackup(String name) { + this.name = name; + } + + public void init() { + if (name == null) + throw new ArgeoException("Atomic backup name must be set"); + } + + public void destroy() { + + } + + @Override + public String backup(FileSystemManager fileSystemManager, + String backupsBase, BackupContext backupContext, + FileSystemOptions opts) { + if (name == null) + throw new ArgeoException("Atomic backup name must be set"); + + FileObject targetFo = null; + try { + if (backupsBase.startsWith("sftp:")) + SftpFileSystemConfigBuilder.getInstance() + .setStrictHostKeyChecking(opts, "no"); + if (compression == null || compression.equals("none")) + targetFo = fileSystemManager.resolveFile(backupsBase + '/' + + backupContext.getRelativeFolder() + '/' + name, opts); + else if (compression.equals("bz2")) + targetFo = fileSystemManager.resolveFile("bz2:" + backupsBase + + '/' + backupContext.getRelativeFolder() + '/' + name + + ".bz2" + "!" + name, opts); + else if (compression.equals("gz")) + targetFo = fileSystemManager.resolveFile("gz:" + backupsBase + + '/' + backupContext.getRelativeFolder() + '/' + name + + ".gz" + "!" + name, opts); + else + throw new ArgeoException("Unsupported compression " + + compression); + + writeBackup(targetFo); + + return targetFo.toString(); + } catch (Exception e) { + throw new ArgeoException("Cannot backup " + name + " to " + + targetFo, e); + } finally { + BackupUtils.closeFOQuietly(targetFo); + } + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setCompression(String compression) { + this.compression = compression; + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/AtomicBackup.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/AtomicBackup.java new file mode 100644 index 000000000..e14344c8f --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/AtomicBackup.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import org.apache.commons.vfs2.FileSystemManager; +import org.apache.commons.vfs2.FileSystemOptions; + +/** Performs the backup of a single component, typically a database dump */ +public interface AtomicBackup { + /** Name identifiying this backup */ + public String getName(); + + /** + * Retrieves the data of the component in a format that allows to restore + * the component + * + * @param backupContext + * the context of this backup + * @return the VFS URI of the generated file or directory + */ + public String backup(FileSystemManager fileSystemManager, + String backupsBase, BackupContext backupContext, + FileSystemOptions opts); +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/BackupContext.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/BackupContext.java new file mode 100644 index 000000000..14e7eb41a --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/BackupContext.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import java.text.DateFormat; +import java.util.Date; + +/** + * Transient information of a given backup, centralizing common information such + * as timestamp and location. + */ +public interface BackupContext { + /** Backup date */ + public Date getTimestamp(); + + /** Formatted backup date */ + public String getTimestampAsString(); + + /** System name */ + public String getSystemName(); + + /** Local base */ + public String getRelativeFolder(); + + /** Date format */ + public DateFormat getDateFormat(); +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/BackupFileSystemManager.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/BackupFileSystemManager.java new file mode 100644 index 000000000..2883e05ed --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/BackupFileSystemManager.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.impl.DefaultFileSystemManager; +import org.apache.commons.vfs2.provider.bzip2.Bzip2FileProvider; +import org.apache.commons.vfs2.provider.ftp.FtpFileProvider; +import org.apache.commons.vfs2.provider.gzip.GzipFileProvider; +import org.apache.commons.vfs2.provider.local.DefaultLocalFileProvider; +import org.apache.commons.vfs2.provider.ram.RamFileProvider; +import org.apache.commons.vfs2.provider.sftp.SftpFileProvider; +import org.apache.commons.vfs2.provider.url.UrlFileProvider; +import org.argeo.ArgeoException; + +/** + * Programatically configured VFS file system manager which can be declared as a + * bean and associated with a life cycle (methods + * {@link DefaultFileSystemManager#init()} and + * {@link DefaultFileSystemManager#closet()}). Supports bz2, file, ram, gzip, + * ftp, sftp + */ +public class BackupFileSystemManager extends DefaultFileSystemManager { + + public BackupFileSystemManager() { + super(); + try { + addProvider("file", new DefaultLocalFileProvider()); + addProvider("bz2", new Bzip2FileProvider()); + addProvider("ftp", new FtpFileProvider()); + addProvider("sftp", new SftpFileProvider()); + addProvider("gzip", new GzipFileProvider()); + addProvider("ram", new RamFileProvider()); + setDefaultProvider(new UrlFileProvider()); + } catch (FileSystemException e) { + throw new ArgeoException("Cannot configure backup file provider", e); + } + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/BackupPurge.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/BackupPurge.java new file mode 100644 index 000000000..75a6b164b --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/BackupPurge.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import java.text.DateFormat; + +import org.apache.commons.vfs2.FileSystemManager; +import org.apache.commons.vfs2.FileSystemOptions; + +/** Purges previous backups */ +public interface BackupPurge { + /** + * Purge the backups identified by these arguments. Although these are the + * same fields as a {@link BackupContext} we don't pass it as argument since + * we want to use this interface to purge remote backups as well (that is, + * with a different base), or outside the scope of a running backup. + */ + public void purge(FileSystemManager fileSystemManager, String base, + String name, DateFormat dateFormat, FileSystemOptions opts); +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/BackupUtils.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/BackupUtils.java new file mode 100644 index 000000000..9a4e91c1f --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/BackupUtils.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import org.apache.commons.vfs2.FileObject; + +/** Backup utilities */ +public class BackupUtils { + /** Close a file object quietly even if it is null or throws an exception. */ + public static void closeFOQuietly(FileObject fo) { + if (fo != null) { + try { + fo.close(); + } catch (Exception e) { + // silent + } + } + } + + /** Prevents instantiation */ + private BackupUtils() { + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/MySqlBackup.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/MySqlBackup.java new file mode 100644 index 000000000..765c56495 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/MySqlBackup.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import org.apache.commons.vfs2.FileObject; + +/** Backups a MySQL database using mysqldump. */ +public class MySqlBackup extends OsCallBackup { + private String mysqldumpLocation = "/usr/bin/mysqldump"; + + private String dbUser; + private String dbPassword; + private String dbName; + + public MySqlBackup() { + } + + public MySqlBackup(String dbUser, String dbPassword, String dbName) { + this.dbUser = dbUser; + this.dbPassword = dbPassword; + this.dbName = dbName; + init(); + } + + @Override + public void init() { + if (getName() == null) + setName(dbName + ".mysql"); + super.init(); + } + + @Override + public void writeBackup(FileObject targetFo) { + if (getCommand() == null) + setCommand(mysqldumpLocation + + " --lock-tables --add-locks --add-drop-table" + + " -u ${dbUser} --password=${dbPassword} --databases ${dbName}"); + getVariables().put("dbUser", dbUser); + getVariables().put("dbPassword", dbPassword); + getVariables().put("dbName", dbName); + + super.writeBackup(targetFo); + } + + public void setDbUser(String dbUser) { + this.dbUser = dbUser; + } + + public void setDbPassword(String dbPassword) { + this.dbPassword = dbPassword; + } + + public void setDbName(String dbName) { + this.dbName = dbName; + } + + public void setMysqldumpLocation(String mysqldumpLocation) { + this.mysqldumpLocation = mysqldumpLocation; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/OpenLdapBackup.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/OpenLdapBackup.java new file mode 100644 index 000000000..278e36276 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/OpenLdapBackup.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import org.apache.commons.vfs2.FileObject; +import org.argeo.ArgeoException; + +/** Backups an OpenLDAP server using slapcat */ +public class OpenLdapBackup extends OsCallBackup { + private String slapcatLocation = "/usr/sbin/slapcat"; + private String slapdConfLocation = "/etc/openldap/slapd.conf"; + private String baseDn; + + public OpenLdapBackup() { + super(); + } + + public OpenLdapBackup(String baseDn) { + super(); + this.baseDn = baseDn; + } + + @Override + public void writeBackup(FileObject targetFo) { + if (baseDn == null) + throw new ArgeoException("Base DN must be set"); + + if (getCommand() == null) + setCommand(slapcatLocation + + " -f ${slapdConfLocation} -b '${baseDn}'"); + getVariables().put("slapdConfLocation", slapdConfLocation); + getVariables().put("baseDn", baseDn); + + super.writeBackup(targetFo); + } + + public void setSlapcatLocation(String slapcatLocation) { + this.slapcatLocation = slapcatLocation; + } + + public void setSlapdConfLocation(String slapdConfLocation) { + this.slapdConfLocation = slapdConfLocation; + } + + public void setBaseDn(String baseDn) { + this.baseDn = baseDn; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/OsCallBackup.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/OsCallBackup.java new file mode 100644 index 000000000..e588a0b2e --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/OsCallBackup.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import java.io.ByteArrayOutputStream; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.exec.CommandLine; +import org.apache.commons.exec.DefaultExecutor; +import org.apache.commons.exec.ExecuteException; +import org.apache.commons.exec.ExecuteStreamHandler; +import org.apache.commons.exec.Executor; +import org.apache.commons.exec.PumpStreamHandler; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.vfs2.FileContent; +import org.apache.commons.vfs2.FileObject; +import org.argeo.ArgeoException; + +/** + * Runs an OS command and save its standard output as a file. Typically used for + * MySQL or OpenLDAP dumps. + */ +public class OsCallBackup extends AbstractAtomicBackup { + private final static Log log = LogFactory.getLog(OsCallBackup.class); + + private String command; + private Map variables = new HashMap(); + private Executor executor = new DefaultExecutor(); + + private Map environment = new HashMap(); + + /** Name of the sudo user, root if "", not sudo if null */ + private String sudo = null; + + public OsCallBackup() { + } + + public OsCallBackup(String name) { + super(name); + } + + public OsCallBackup(String name, String command) { + super(name); + this.command = command; + } + + @Override + public void writeBackup(FileObject targetFo) { + String commandToUse = command; + + // sudo + if (sudo != null) { + if (sudo.equals("")) + commandToUse = "sudo " + commandToUse; + else + commandToUse = "sudo -u " + sudo + " " + commandToUse; + } + + CommandLine commandLine = CommandLine.parse(commandToUse, variables); + ByteArrayOutputStream errBos = new ByteArrayOutputStream(); + if (log.isTraceEnabled()) + log.trace(commandLine.toString()); + + try { + // stdout + FileContent targetContent = targetFo.getContent(); + // stderr + ExecuteStreamHandler streamHandler = new PumpStreamHandler( + targetContent.getOutputStream(), errBos); + executor.setStreamHandler(streamHandler); + executor.execute(commandLine, environment); + } catch (ExecuteException e) { + byte[] err = errBos.toByteArray(); + String errStr = new String(err); + throw new ArgeoException("Process " + commandLine + " failed (" + + e.getExitValue() + "): " + errStr, e); + } catch (Exception e) { + byte[] err = errBos.toByteArray(); + String errStr = new String(err); + throw new ArgeoException("Process " + commandLine + " failed: " + + errStr, e); + } finally { + IOUtils.closeQuietly(errBos); + } + } + + public void setCommand(String command) { + this.command = command; + } + + protected String getCommand() { + return command; + } + + /** + * A reference to the environment variables that will be passed to the + * process. Empty by default. + */ + protected Map getEnvironment() { + return environment; + } + + protected Map getVariables() { + return variables; + } + + public void setVariables(Map variables) { + this.variables = variables; + } + + public void setExecutor(Executor executor) { + this.executor = executor; + } + + public void setSudo(String sudo) { + this.sudo = sudo; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/PostgreSqlBackup.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/PostgreSqlBackup.java new file mode 100644 index 000000000..dbc3624fb --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/PostgreSqlBackup.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import org.apache.commons.vfs2.FileObject; + +/** Backups a PostgreSQL database using pg_dump. */ +public class PostgreSqlBackup extends OsCallBackup { + /** + * PostgreSQL password environment variable (see + * http://stackoverflow.com/questions + * /2893954/how-to-pass-in-password-to-pg-dump) + */ + protected final static String PGPASSWORD = "PGPASSWORD"; + + private String pgDumpLocation = "/usr/bin/pg_dump"; + + private String dbUser; + private String dbPassword; + private String dbName; + + public PostgreSqlBackup() { + super(); + } + + public PostgreSqlBackup(String dbUser, String dbPassword, String dbName) { + this.dbUser = dbUser; + this.dbPassword = dbPassword; + this.dbName = dbName; + init(); + } + + @Override + public void init() { + // disable compression since pg_dump is used with -Fc option + setCompression(null); + + if (getName() == null) + setName(dbName + ".pgdump"); + super.init(); + } + + @Override + public void writeBackup(FileObject targetFo) { + if (getCommand() == null) { + getEnvironment().put(PGPASSWORD, dbPassword); + setCommand(pgDumpLocation + " -Fc" + " -U ${dbUser} ${dbName}"); + } + getVariables().put("dbUser", dbUser); + getVariables().put("dbPassword", dbPassword); + getVariables().put("dbName", dbName); + + super.writeBackup(targetFo); + } + + public void setDbUser(String dbUser) { + this.dbUser = dbUser; + } + + public void setDbPassword(String dbPassword) { + this.dbPassword = dbPassword; + } + + public void setDbName(String dbName) { + this.dbName = dbName; + } + + public void setPgDumpLocation(String mysqldumpLocation) { + this.pgDumpLocation = mysqldumpLocation; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/SimpleBackupContext.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/SimpleBackupContext.java new file mode 100644 index 000000000..8e9e418f0 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/SimpleBackupContext.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.apache.commons.vfs2.FileSystemManager; + +/** Simple implementation of a backup context */ +public class SimpleBackupContext implements BackupContext { + private DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmm"); + private final Date timestamp; + private final String name; + + private final FileSystemManager fileSystemManager; + + public SimpleBackupContext(FileSystemManager fileSystemManager, + String backupsBase, String name) { + this.name = name; + this.timestamp = new Date(); + this.fileSystemManager = fileSystemManager; + } + + public Date getTimestamp() { + return timestamp; + } + + public String getTimestampAsString() { + return dateFormat.format(timestamp); + } + + public String getSystemName() { + return name; + } + + public String getRelativeFolder() { + return name + '/' + getTimestampAsString(); + } + + public DateFormat getDateFormat() { + return dateFormat; + } + + public FileSystemManager getFileSystemManager() { + return fileSystemManager; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/SimpleBackupPurge.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/SimpleBackupPurge.java new file mode 100644 index 000000000..64d749bee --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/SimpleBackupPurge.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import java.text.DateFormat; +import java.util.Date; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemManager; +import org.apache.commons.vfs2.FileSystemOptions; +import org.apache.commons.vfs2.Selectors; +import org.argeo.ArgeoException; +import org.joda.time.DateTime; +import org.joda.time.Period; + +/** Simple backup purge which keeps backups only for a given number of days */ +public class SimpleBackupPurge implements BackupPurge { + private final static Log log = LogFactory.getLog(SimpleBackupPurge.class); + + private Integer daysKept = 30; + + @Override + public void purge(FileSystemManager fileSystemManager, String base, + String name, DateFormat dateFormat, FileSystemOptions opts) { + try { + DateTime nowDt = new DateTime(); + FileObject baseFo = fileSystemManager.resolveFile( + base + '/' + name, opts); + + SortedMap toDelete = new TreeMap(); + int backupCount = 0; + + // make sure base dir exists + baseFo.createFolder(); + + // scan backups and list those which should be deleted + for (FileObject backupFo : baseFo.getChildren()) { + String backupName = backupFo.getName().getBaseName(); + Date backupDate = dateFormat.parse(backupName); + backupCount++; + + DateTime backupDt = new DateTime(backupDate.getTime()); + Period sinceThen = new Period(backupDt, nowDt); + int days = sinceThen.getDays(); + // int days = sinceThen.getMinutes(); + if (days > daysKept) { + toDelete.put(backupDt, backupFo); + } + } + + if (toDelete.size() != 0 && toDelete.size() == backupCount) { + // all backups would be deleted + // but we want to keep at least one + DateTime lastBackupDt = toDelete.firstKey(); + FileObject keptFo = toDelete.remove(lastBackupDt); + log.warn("Backup " + keptFo + + " kept although it is older than " + daysKept + + " days."); + } + + // delete old backups + for (FileObject backupFo : toDelete.values()) { + backupFo.delete(Selectors.SELECT_ALL); + if (log.isDebugEnabled()) + log.debug("Deleted backup " + backupFo); + } + } catch (Exception e) { + throw new ArgeoException("Could not purge previous backups", e); + } + + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/SvnBackup.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/SvnBackup.java new file mode 100644 index 000000000..7367c04c6 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/SvnBackup.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import java.io.File; + +import org.apache.commons.vfs2.FileObject; + +/** Backups a Subversion repository using svnadmin. */ +public class SvnBackup extends OsCallBackup { + private String svnadminLocation = "/usr/bin/svnadmin"; + + private String repoLocation; + private String repoName; + + public SvnBackup() { + } + + public SvnBackup(String repoLocation) { + this.repoLocation = repoLocation; + init(); + } + + @Override + public void init() { + // use directory as repo name + if (repoName == null) + repoName = new File(repoLocation).getName(); + + if (getName() == null) + setName(repoName + ".svndump"); + super.init(); + } + + @Override + public void writeBackup(FileObject targetFo) { + if (getCommand() == null) { + setCommand(svnadminLocation + " dump " + " ${repoLocation}"); + } + getVariables().put("repoLocation", repoLocation); + + super.writeBackup(targetFo); + } + + public void setRepoLocation(String repoLocation) { + this.repoLocation = repoLocation; + } + + public void setRepoName(String repoName) { + this.repoName = repoName; + } + + public void setSvnadminLocation(String mysqldumpLocation) { + this.svnadminLocation = mysqldumpLocation; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/backup/SystemBackup.java b/org.argeo.cms/src/org/argeo/cms/internal/backup/SystemBackup.java new file mode 100644 index 000000000..5036cc481 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/backup/SystemBackup.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.cms.internal.backup; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.FileSystemException; +import org.apache.commons.vfs2.FileSystemManager; +import org.apache.commons.vfs2.FileSystemOptions; +import org.apache.commons.vfs2.Selectors; +import org.apache.commons.vfs2.UserAuthenticator; +import org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder; +import org.argeo.ArgeoException; + +/** + * Combines multiple backups and transfer them to a remote location. Purges + * remote and local data based on certain criteria. + */ +public class SystemBackup implements Runnable { + private final static Log log = LogFactory.getLog(SystemBackup.class); + + private FileSystemManager fileSystemManager; + private UserAuthenticator userAuthenticator = null; + + private String backupsBase; + private String systemName; + + private List atomicBackups = new ArrayList(); + private BackupPurge backupPurge = new SimpleBackupPurge(); + + private Map remoteBases = new HashMap(); + + @Override + public void run() { + if (atomicBackups.size() == 0) + throw new ArgeoException("No atomic backup listed"); + List failures = new ArrayList(); + + SimpleBackupContext backupContext = new SimpleBackupContext( + fileSystemManager, backupsBase, systemName); + + // purge older backups + FileSystemOptions opts = new FileSystemOptions(); + try { + DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator( + opts, userAuthenticator); + } catch (FileSystemException e) { + throw new ArgeoException("Cannot create authentication", e); + } + + try { + + backupPurge.purge(fileSystemManager, backupsBase, systemName, + backupContext.getDateFormat(), opts); + } catch (Exception e) { + failures.add("Purge " + backupsBase + " failed: " + e.getMessage()); + log.error("Purge of " + backupsBase + " failed", e); + } + + // perform backup + for (AtomicBackup atomickBackup : atomicBackups) { + try { + String target = atomickBackup.backup(fileSystemManager, + backupsBase, backupContext, opts); + if (log.isDebugEnabled()) + log.debug("Performed backup " + target); + } catch (Exception e) { + String msg = "Atomic backup " + atomickBackup.getName() + + " failed: " + ArgeoException.chainCausesMessages(e); + failures.add(msg); + log.error(msg); + if (log.isTraceEnabled()) + log.trace( + "Stacktrace of atomic backup " + + atomickBackup.getName() + " failure.", e); + } + } + + // dispatch to remote + for (String remoteBase : remoteBases.keySet()) { + FileObject localBaseFo = null; + FileObject remoteBaseFo = null; + UserAuthenticator auth = remoteBases.get(remoteBase); + + // authentication + FileSystemOptions remoteOpts = new FileSystemOptions(); + try { + DefaultFileSystemConfigBuilder.getInstance() + .setUserAuthenticator(remoteOpts, auth); + backupPurge.purge(fileSystemManager, remoteBase, systemName, + backupContext.getDateFormat(), remoteOpts); + } catch (Exception e) { + failures.add("Purge " + remoteBase + " failed: " + + e.getMessage()); + log.error("Cannot purge " + remoteBase, e); + } + + try { + localBaseFo = fileSystemManager.resolveFile(backupsBase + '/' + + backupContext.getRelativeFolder(), opts); + remoteBaseFo = fileSystemManager.resolveFile(remoteBase + '/' + + backupContext.getRelativeFolder(), remoteOpts); + remoteBaseFo.copyFrom(localBaseFo, Selectors.SELECT_ALL); + if (log.isDebugEnabled()) + log.debug("Copied backup to " + remoteBaseFo + " from " + + localBaseFo); + // } + } catch (Exception e) { + failures.add("Dispatch to " + remoteBase + " failed: " + + e.getMessage()); + log.error( + "Cannot dispatch backups from " + + backupContext.getRelativeFolder() + " to " + + remoteBase, e); + } + BackupUtils.closeFOQuietly(localBaseFo); + BackupUtils.closeFOQuietly(remoteBaseFo); + } + + int failureCount = 0; + if (failures.size() > 0) { + StringBuffer buf = new StringBuffer(); + for (String failure : failures) { + buf.append('\n').append(failureCount).append(" - ") + .append(failure); + failureCount++; + } + throw new ArgeoException(failureCount + + " error(s) when running the backup," + + " check the logs and the backups as soon as possible." + + buf); + } + } + + public void setFileSystemManager(FileSystemManager fileSystemManager) { + this.fileSystemManager = fileSystemManager; + } + + public void setBackupsBase(String backupsBase) { + this.backupsBase = backupsBase; + } + + public void setSystemName(String name) { + this.systemName = name; + } + + public void setAtomicBackups(List atomicBackups) { + this.atomicBackups = atomicBackups; + } + + public void setBackupPurge(BackupPurge backupPurge) { + this.backupPurge = backupPurge; + } + + public void setUserAuthenticator(UserAuthenticator userAuthenticator) { + this.userAuthenticator = userAuthenticator; + } + + public void setRemoteBases(Map remoteBases) { + this.remoteBases = remoteBases; + } + +// public static void main(String args[]) { +// while (true) { +// try { +// StandardFileSystemManager fsm = new StandardFileSystemManager(); +// fsm.init(); +// +// SystemBackup systemBackup = new SystemBackup(); +// systemBackup.setSystemName("mySystem"); +// systemBackup +// .setBackupsBase("/home/mbaudier/dev/src/commons/server/runtime/org.argeo.server.core/target"); +// systemBackup.setFileSystemManager(fsm); +// +// List atomicBackups = new ArrayList(); +// +// MySqlBackup mySqlBackup = new MySqlBackup("root", "", "test"); +// atomicBackups.add(mySqlBackup); +// PostgreSqlBackup postgreSqlBackup = new PostgreSqlBackup( +// "argeo", "argeo", "gis_template"); +// atomicBackups.add(postgreSqlBackup); +// SvnBackup svnBackup = new SvnBackup( +// "/home/mbaudier/tmp/testsvnrepo"); +// atomicBackups.add(svnBackup); +// +// systemBackup.setAtomicBackups(atomicBackups); +// +// Map remoteBases = new HashMap(); +// StaticUserAuthenticator userAuthenticator = new StaticUserAuthenticator( +// null, "demo", "demo"); +// remoteBases.put("sftp://localhost/home/mbaudier/test", +// userAuthenticator); +// systemBackup.setRemoteBases(remoteBases); +// +// systemBackup.run(); +// +// fsm.close(); +// } catch (FileSystemException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// System.exit(1); +// } +// +// // wait +// try { +// Thread.sleep(120 * 1000); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// } +// } +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java index c0383f543..db66de2ea 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttp.java @@ -15,8 +15,6 @@ import org.apache.commons.codec.binary.Base64; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.cms.CmsException; -import org.argeo.cms.internal.kernel.NodeHttp.AnonymousFilter; -import org.argeo.cms.internal.kernel.NodeHttp.DavFilter; import org.argeo.jackrabbit.servlet.OpenInViewSessionProvider; import org.argeo.jackrabbit.servlet.RemotingServlet; import org.argeo.jackrabbit.servlet.WebdavServlet; @@ -52,7 +50,7 @@ class NodeHttp implements KernelConstants, ArgeoJcrConstants { private String httpAuthRealm = "Argeo"; // Filters - private final RootFilter rootFilter; + // private final RootFilter rootFilter; // remoting private OpenInViewSessionProvider sessionProvider; @@ -81,7 +79,7 @@ class NodeHttp implements KernelConstants, ArgeoJcrConstants { + ExtendedHttpService.class + " service."); // Filters - rootFilter = new RootFilter(); + // rootFilter = new RootFilter(); // DAV sessionProvider = new OpenInViewSessionProvider(); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java index b5d2eb412..be94cd5df 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java @@ -30,12 +30,15 @@ class NodeSecurity implements AuthenticationManager { private final InternalAuthenticationProvider internalAuth; private final AnonymousAuthenticationProvider anonymousAuth; - private final JackrabbitUserAdminService jackrabbitUserAdmin; + private final JackrabbitUserAdminService userAdminService; + // private final JcrUserAdmin userAdmin; private ServiceRegistration authenticationManagerReg; - private ServiceRegistration userAdminReg; + private ServiceRegistration userAdminServiceReg; private ServiceRegistration userDetailsManagerReg; + // private ServiceRegistration userAdminReg; + public NodeSecurity(BundleContext bundleContext, JackrabbitNode node) throws RepositoryException { URL url = getClass().getClassLoader().getResource( @@ -51,33 +54,36 @@ class NodeSecurity implements AuthenticationManager { KernelConstants.DEFAULT_SECURITY_KEY); // user admin - jackrabbitUserAdmin = new JackrabbitUserAdminService(); - jackrabbitUserAdmin.setRepository(node); - jackrabbitUserAdmin.setSecurityModel(new SimpleJcrSecurityModel()); - jackrabbitUserAdmin.init(); + userAdminService = new JackrabbitUserAdminService(); + userAdminService.setRepository(node); + userAdminService.setSecurityModel(new SimpleJcrSecurityModel()); + userAdminService.init(); + + // userAdmin = new JcrUserAdmin(bundleContext); + // userAdmin.setUserAdminService(userAdminService); } public void publish() { authenticationManagerReg = bundleContext.registerService( AuthenticationManager.class, this, null); - userAdminReg = bundleContext.registerService(UserAdminService.class, - jackrabbitUserAdmin, null); + userAdminServiceReg = bundleContext.registerService( + UserAdminService.class, userAdminService, null); userDetailsManagerReg = bundleContext.registerService( - UserDetailsManager.class, jackrabbitUserAdmin, null); - // userAdminReg = - // bundleContext.registerService(UserDetailsService.class, - // jackrabbitUserAdmin, null); + UserDetailsManager.class, userAdminService, null); + // userAdminReg = bundleContext.registerService(UserAdmin.class, + // userAdmin, null); } void destroy() { try { - jackrabbitUserAdmin.destroy(); + userAdminService.destroy(); } catch (RepositoryException e) { log.error("Error while destroying Jackrabbit useradmin"); } userDetailsManagerReg.unregister(); - userAdminReg.unregister(); + userAdminServiceReg.unregister(); authenticationManagerReg.unregister(); + // userAdminReg.unregister(); } @Override @@ -89,7 +95,7 @@ class NodeSecurity implements AuthenticationManager { else if (authentication instanceof AnonymousAuthenticationToken) auth = anonymousAuth.authenticate(authentication); else if (authentication instanceof UsernamePasswordAuthenticationToken) - auth = jackrabbitUserAdmin.authenticate(authentication); + auth = userAdminService.authenticate(authentication); if (auth == null) throw new CmsException("Could not authenticate " + authentication); return auth; diff --git a/org.argeo.cms/src/org/argeo/cms/viewers/AbstractPageViewer.java b/org.argeo.cms/src/org/argeo/cms/viewers/AbstractPageViewer.java index e779a7993..331275c44 100644 --- a/org.argeo.cms/src/org/argeo/cms/viewers/AbstractPageViewer.java +++ b/org.argeo.cms/src/org/argeo/cms/viewers/AbstractPageViewer.java @@ -10,7 +10,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.cms.CmsEditable; import org.argeo.cms.CmsException; -import org.argeo.cms.widgets.JcrComposite; import org.argeo.cms.widgets.ScrolledPage; import org.eclipse.jface.viewers.ContentViewer; import org.eclipse.jface.viewers.ISelection; diff --git a/org.argeo.eclipse.ui.rap/pom.xml b/org.argeo.eclipse.ui.rap/pom.xml index 167f2d3e3..d164dbc96 100644 --- a/org.argeo.eclipse.ui.rap/pom.xml +++ b/org.argeo.eclipse.ui.rap/pom.xml @@ -9,33 +9,16 @@ org.argeo.eclipse.ui.rap Commons Eclipse UI RAP - Provide rap specific classes and behaviour in order to provide single sourcing abilities - jar - org.argeo.commons org.argeo.eclipse.ui 2.1.14-SNAPSHOT - - - - - org.argeo.commons org.argeo.util 2.1.14-SNAPSHOT - - - - \ No newline at end of file diff --git a/org.argeo.eclipse.ui.workbench.rap/pom.xml b/org.argeo.eclipse.ui.workbench.rap/pom.xml index a1f59ea9e..3977949dc 100644 --- a/org.argeo.eclipse.ui.workbench.rap/pom.xml +++ b/org.argeo.eclipse.ui.workbench.rap/pom.xml @@ -7,5 +7,5 @@ .. org.argeo.eclipse.ui.workbench.rap - Commons Eclipse UI Workbench RAP + Commons Eclipse Workbench RAP diff --git a/org.argeo.eclipse.ui.workbench/pom.xml b/org.argeo.eclipse.ui.workbench/pom.xml index 360054f33..bde063db0 100644 --- a/org.argeo.eclipse.ui.workbench/pom.xml +++ b/org.argeo.eclipse.ui.workbench/pom.xml @@ -7,44 +7,23 @@ .. org.argeo.eclipse.ui.workbench - Commons Eclipse UI Workbench + Commons Eclipse Workbench - org.argeo.commons - org.argeo.eclipse.ui + org.argeo.util 2.1.14-SNAPSHOT - - - - - - org.argeo.commons - org.argeo.eclipse.ui.rap + org.argeo.eclipse.ui 2.1.14-SNAPSHOT - provided - - - - org.argeo.commons - org.argeo.util + org.argeo.eclipse.ui.rap 2.1.14-SNAPSHOT + provided - + \ No newline at end of file diff --git a/org.argeo.eclipse.ui/bnd.bnd b/org.argeo.eclipse.ui/bnd.bnd index 32bfbc1ad..bf8d37a8f 100644 --- a/org.argeo.eclipse.ui/bnd.bnd +++ b/org.argeo.eclipse.ui/bnd.bnd @@ -1,4 +1,3 @@ -Require-Bundle: org.eclipse.core.runtime Import-Package: org.eclipse.core.commands,\ org.eclipse.jface.window,\ org.eclipse.swt,\ @@ -11,12 +10,3 @@ Import-Package: org.eclipse.core.commands,\ javax.jcr.nodetype,\ org.springframework.security.core,\ * - -# Was: -#Bundle-ActivationPolicy: lazy -#Bundle-SymbolicName: org.argeo.eclipse.ui;singleton:=true -#Bundle-Activator: org.argeo.eclipse.ui.ArgeoUiPlugin - -#!org.eclipse.core.commands,\ -# !org.eclipse.core.runtime,\ -# !org.eclipse.ui.plugin,\ diff --git a/org.argeo.eclipse.ui/pom.xml b/org.argeo.eclipse.ui/pom.xml index d352a32ec..7a6d53505 100644 --- a/org.argeo.eclipse.ui/pom.xml +++ b/org.argeo.eclipse.ui/pom.xml @@ -9,16 +9,7 @@ org.argeo.eclipse.ui Commons Eclipse UI - jar - - - - org.argeo.commons org.argeo.util @@ -34,24 +25,5 @@ org.argeo.security.core 2.1.14-SNAPSHOT - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.security.core/bnd.bnd b/org.argeo.security.core/bnd.bnd index ef3d1aa2e..fa20c3d9e 100644 --- a/org.argeo.security.core/bnd.bnd +++ b/org.argeo.security.core/bnd.bnd @@ -3,4 +3,6 @@ Import-Package:org.bouncycastle.*;resolution:=optional,\ org.springframework.util,\ javax.jcr.security,\ org.apache.jackrabbit.*;resolution:=optional,\ +org.springframework.ldap.*;resolution:=optional,\ +org.springframework.security.ldap.*;resolution:=optional,\ * diff --git a/org.argeo.security.core/pom.xml b/org.argeo.security.core/pom.xml index b677bb860..426fc9ff1 100644 --- a/org.argeo.security.core/pom.xml +++ b/org.argeo.security.core/pom.xml @@ -8,7 +8,7 @@ .. org.argeo.security.core - Commons Security Core + Commons Security org.argeo.commons @@ -20,96 +20,5 @@ org.argeo.server.jcr 2.1.14-SNAPSHOT - - org.argeo.commons - org.argeo.server.jackrabbit - 2.1.14-SNAPSHOT - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.security.core/src/org/argeo/security/core/AuthorizationPrincipal.java b/org.argeo.security.core/src/org/argeo/security/core/AuthorizationPrincipal.java new file mode 100644 index 000000000..ac3b23369 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/security/core/AuthorizationPrincipal.java @@ -0,0 +1,24 @@ +package org.argeo.security.core; + +import java.security.Principal; + +import org.osgi.service.useradmin.Authorization; + +/** Wraps an OSGi {@link Authorization} as a JAAS {@link Principal} */ +public final class AuthorizationPrincipal implements Principal { + private Authorization authorization; + + public AuthorizationPrincipal(Authorization authorization) { + this.authorization = authorization; + } + + @Override + public String getName() { + return authorization.getName(); + } + + public Authorization getAuthorization() { + return authorization; + } + +} diff --git a/org.argeo.security.core/src/org/argeo/security/core/UserAdminLoginModule.java b/org.argeo.security.core/src/org/argeo/security/core/UserAdminLoginModule.java new file mode 100644 index 000000000..16bc623d6 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/security/core/UserAdminLoginModule.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.security.core; + +import java.util.Locale; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.LoginException; +import javax.security.auth.spi.LoginModule; + +import org.argeo.jcr.ArgeoNames; +import org.argeo.util.LocaleCallback; +import org.argeo.util.LocaleUtils; +import org.osgi.framework.BundleContext; +import org.osgi.service.useradmin.Authorization; +import org.osgi.service.useradmin.User; +import org.osgi.service.useradmin.UserAdmin; +import org.springframework.security.authentication.encoding.LdapShaPasswordEncoder; + +/** Login module which caches one subject per thread. */ +public class UserAdminLoginModule implements LoginModule { + // private final static Log log = LogFactory + // .getLog(UserAdminLoginModule.class); + + private CallbackHandler callbackHandler; + + private Subject subject; + + private Long waitBetweenFailedLoginAttempts = 5 * 1000l; + + /** Comma separated list of locales */ + private String availableLocales = ""; + + private AuthorizationPrincipal auth = null; + private Locale selectedLocale = null; + + private LdapShaPasswordEncoder shaPasswordEncoder = new LdapShaPasswordEncoder(); + + public UserAdminLoginModule() { + + } + + @SuppressWarnings("rawtypes") + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) { + this.callbackHandler = callbackHandler; + this.subject = subject; + } + + public boolean login() throws LoginException { + try { + // TODO thread already logged in + // AuthorizationPrincipal principal = subject + // .getPrincipals(AuthorizationPrincipal.class).iterator(); + + if (callbackHandler == null) + throw new LoginException("No call back handler available"); + + // ask for username and password + NameCallback nameCallback = new NameCallback("User"); + PasswordCallback passwordCallback = new PasswordCallback( + "Password", false); + LocaleCallback localeCallback = new LocaleCallback(availableLocales); + BundleContextCallback bundleContextCallback = new BundleContextCallback(); + + callbackHandler.handle(new Callback[] { nameCallback, + passwordCallback, localeCallback, bundleContextCallback }); + + selectedLocale = localeCallback.getSelectedLocale(); + + // create credentials + final String username = nameCallback.getName(); + if (username == null || username.trim().equals("")) + return false; + + char[] password = {}; + if (passwordCallback.getPassword() != null) + password = passwordCallback.getPassword(); + + BundleContext bc = bundleContextCallback.getBundleContext(); + UserAdmin userAdmin = bc.getService(bc + .getServiceReference(UserAdmin.class)); + + User user = (User) userAdmin.getRole(username); + // TODO use hash + boolean authenticated = user.hasCredential( + ArgeoNames.ARGEO_PASSWORD, new String(password)); + + if (!authenticated) { + // wait between failed login attempts + Thread.sleep(waitBetweenFailedLoginAttempts); + return false; + } + + Authorization authorization = userAdmin.getAuthorization(user); + auth = new AuthorizationPrincipal(authorization); + return true; + } catch (LoginException e) { + throw e; + } catch (ThreadDeath e) { + LoginException le = new LoginException( + "Spring Security login thread died"); + le.initCause(e); + throw le; + } catch (Exception e) { + LoginException le = new LoginException( + "Spring Security login failed"); + le.initCause(e); + throw le; + } + } + + @Override + public boolean logout() throws LoginException { + subject.getPrincipals(AuthorizationPrincipal.class).remove(auth); + return true; + } + + @Override + public boolean commit() throws LoginException { + subject.getPrincipals().add(auth); + if (selectedLocale != null) + LocaleUtils.threadLocale.set(selectedLocale); + return true; + } + + @Override + public boolean abort() throws LoginException { + auth = null; + selectedLocale = null; + return true; + } + + public void setAvailableLocales(String locales) { + this.availableLocales = locales; + } +} \ No newline at end of file diff --git a/org.argeo.security.core/src/org/argeo/security/ldap/ArgeoLdapShaPasswordEncoder.java b/org.argeo.security.core/src/org/argeo/security/ldap/ArgeoLdapShaPasswordEncoder.java new file mode 100644 index 000000000..a2c43a589 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/security/ldap/ArgeoLdapShaPasswordEncoder.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.security.ldap; + +import org.springframework.security.authentication.encoding.LdapShaPasswordEncoder; + +/** + * {@link LdapShaPasswordEncoder} allowing to configure the usage of salt (APache + * Directory Server 1.0 does not support bind with SSHA) + */ +public class ArgeoLdapShaPasswordEncoder extends LdapShaPasswordEncoder { + private Boolean useSalt = true; + + @Override + public String encodePassword(String rawPass, Object salt) { + return super.encodePassword(rawPass, useSalt ? salt : null); + } + + public void setUseSalt(Boolean useSalt) { + this.useSalt = useSalt; + } + +} diff --git a/org.argeo.security.core/src/org/argeo/security/ldap/ArgeoLdapUserDetailsManager.java b/org.argeo.security.core/src/org/argeo/security/ldap/ArgeoLdapUserDetailsManager.java new file mode 100644 index 000000000..89b5aa92d --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/security/ldap/ArgeoLdapUserDetailsManager.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.security.ldap; + +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.TreeSet; + +import org.argeo.ArgeoException; +import org.argeo.security.UserAdminService; +import org.springframework.ldap.core.ContextSource; +import org.springframework.security.authentication.encoding.PasswordEncoder; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.ldap.userdetails.LdapUserDetailsManager; + +/** Extends {@link LdapUserDetailsManager} by adding password encoding support. */ +public class ArgeoLdapUserDetailsManager extends LdapUserDetailsManager + implements UserAdminService { + private String superUsername = "root"; + private ArgeoUserAdminDaoLdap userAdminDao; + private PasswordEncoder passwordEncoder; + private final Random random; + + public ArgeoLdapUserDetailsManager(ContextSource contextSource) { + super(contextSource); + this.random = createRandom(); + } + + private static Random createRandom() { + try { + return SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + return new Random(System.currentTimeMillis()); + } + } + + @Override + public void changePassword(String oldPassword, String newPassword) { + Authentication authentication = SecurityContextHolder.getContext() + .getAuthentication(); + if (authentication == null) + throw new ArgeoException( + "Cannot change password without authentication"); + String username = authentication.getName(); + UserDetails userDetails = loadUserByUsername(username); + String currentPassword = userDetails.getPassword(); + if (currentPassword == null) + throw new ArgeoException("Cannot access current password"); + if (!passwordEncoder + .isPasswordValid(currentPassword, oldPassword, null)) + throw new ArgeoException("Old password invalid"); + // Spring Security LDAP 2.0 is buggy when used with OpenLDAP and called + // with oldPassword argument + super.changePassword(null, encodePassword(newPassword)); + } + + public void newRole(String role) { + userAdminDao.createRole(role, superUsername); + } + + public void synchronize() { + for (String username : userAdminDao.listUsers()) + loadUserByUsername(username); + // TODO: find a way to remove from JCR + } + + public void deleteRole(String role) { + userAdminDao.deleteRole(role); + } + + public Set listUsers() { + return userAdminDao.listUsers(); + } + + public Set listUsersInRole(String role) { + Set lst = new TreeSet( + userAdminDao.listUsersInRole(role)); + Iterator it = lst.iterator(); + while (it.hasNext()) { + if (it.next().equals(superUsername)) { + it.remove(); + break; + } + } + return lst; + } + + public List listUserRoles(String username) { + UserDetails userDetails = loadUserByUsername(username); + List roles = new ArrayList(); + for (GrantedAuthority ga : userDetails.getAuthorities()) { + roles.add(ga.getAuthority()); + } + return Collections.unmodifiableList(roles); + } + + public Set listEditableRoles() { + return userAdminDao.listEditableRoles(); + } + + protected String encodePassword(String password) { + if (!password.startsWith("{")) { + byte[] salt = new byte[16]; + random.nextBytes(salt); + return passwordEncoder.encodePassword(password, salt); + } else { + return password; + } + } + + public void setPasswordEncoder(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + + public void setSuperUsername(String superUsername) { + this.superUsername = superUsername; + } + + public void setUserAdminDao(ArgeoUserAdminDaoLdap userAdminDao) { + this.userAdminDao = userAdminDao; + } + +} diff --git a/org.argeo.security.core/src/org/argeo/security/ldap/ArgeoUserAdminDaoLdap.java b/org.argeo.security.core/src/org/argeo/security/ldap/ArgeoUserAdminDaoLdap.java new file mode 100644 index 000000000..37d2a06a0 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/security/ldap/ArgeoUserAdminDaoLdap.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.security.ldap; + +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; + +import org.springframework.ldap.core.ContextExecutor; +import org.springframework.ldap.core.ContextMapper; +import org.springframework.ldap.core.DirContextAdapter; +import org.springframework.ldap.core.DistinguishedName; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.core.support.BaseLdapPathContextSource; +import org.springframework.security.ldap.LdapUsernameToDnMapper; +import org.springframework.security.ldap.LdapUtils; + +/** + * Wraps low-level LDAP operation on user and roles, used by + * {@link ArgeoLdapUserDetailsManager} + */ +public class ArgeoUserAdminDaoLdap { + private String userBase; + private String usernameAttribute; + private String groupBase; + private String[] groupClasses; + + private String groupRoleAttribute; + private String groupMemberAttribute; + private String defaultRole; + private String rolePrefix; + + private final LdapTemplate ldapTemplate; + private LdapUsernameToDnMapper usernameMapper; + + /** + * Standard constructor, using the LDAP context source shared with Spring + * Security components. + */ + public ArgeoUserAdminDaoLdap(BaseLdapPathContextSource contextSource) { + this.ldapTemplate = new LdapTemplate(contextSource); + } + + @SuppressWarnings("unchecked") + public synchronized Set listUsers() { + List usernames = (List) ldapTemplate.listBindings( + new DistinguishedName(userBase), new ContextMapper() { + public Object mapFromContext(Object ctxArg) { + DirContextAdapter ctx = (DirContextAdapter) ctxArg; + return ctx.getStringAttribute(usernameAttribute); + } + }); + + return Collections + .unmodifiableSortedSet(new TreeSet(usernames)); + } + + @SuppressWarnings("unchecked") + public Set listEditableRoles() { + return Collections.unmodifiableSortedSet(new TreeSet( + ldapTemplate.listBindings(groupBase, new ContextMapper() { + public Object mapFromContext(Object ctxArg) { + String groupName = ((DirContextAdapter) ctxArg) + .getStringAttribute(groupRoleAttribute); + String roleName = convertGroupToRole(groupName); + return roleName; + } + }))); + } + + @SuppressWarnings("unchecked") + public Set listUsersInRole(String role) { + return (Set) ldapTemplate.lookup( + buildGroupDn(convertRoleToGroup(role)), new ContextMapper() { + public Object mapFromContext(Object ctxArg) { + DirContextAdapter ctx = (DirContextAdapter) ctxArg; + String[] userDns = ctx + .getStringAttributes(groupMemberAttribute); + TreeSet set = new TreeSet(); + for (String userDn : userDns) { + DistinguishedName dn = new DistinguishedName(userDn); + String username = dn.getValue(usernameAttribute); + set.add(username); + } + return Collections.unmodifiableSortedSet(set); + } + }); + } + + public void createRole(String role, final String superuserName) { + String group = convertRoleToGroup(role); + DistinguishedName superuserDn = (DistinguishedName) ldapTemplate + .executeReadWrite(new ContextExecutor() { + public Object executeWithContext(DirContext ctx) + throws NamingException { + return LdapUtils.getFullDn( + usernameMapper.buildDn(superuserName), ctx); + } + }); + + Name groupDn = buildGroupDn(group); + DirContextAdapter context = new DirContextAdapter(); + context.setAttributeValues("objectClass", groupClasses); + context.setAttributeValue("cn", group); + // Add superuser because cannot create empty group + context.setAttributeValue(groupMemberAttribute, superuserDn.toString()); + ldapTemplate.bind(groupDn, context, null); + } + + public void deleteRole(String role) { + String group = convertRoleToGroup(role); + Name dn = buildGroupDn(group); + ldapTemplate.unbind(dn); + } + + /** Maps a role (ROLE_XXX) to the related LDAP group (xxx) */ + protected String convertRoleToGroup(String role) { + String group = role; + if (group.startsWith(rolePrefix)) { + group = group.substring(rolePrefix.length()); + group = group.toLowerCase(); + } + return group; + } + + /** Maps anLDAP group (xxx) to the related role (ROLE_XXX) */ + protected String convertGroupToRole(String groupName) { + groupName = groupName.toUpperCase(); + + return rolePrefix + groupName; + } + + protected Name buildGroupDn(String name) { + return new DistinguishedName(groupRoleAttribute + "=" + name + "," + + groupBase); + } + + public void setUserBase(String userBase) { + this.userBase = userBase; + } + + public void setUsernameAttribute(String usernameAttribute) { + this.usernameAttribute = usernameAttribute; + } + + public void setGroupBase(String groupBase) { + this.groupBase = groupBase; + } + + public void setGroupRoleAttribute(String groupRoleAttributeName) { + this.groupRoleAttribute = groupRoleAttributeName; + } + + public void setGroupMemberAttribute(String groupMemberAttributeName) { + this.groupMemberAttribute = groupMemberAttributeName; + } + + public void setDefaultRole(String defaultRole) { + this.defaultRole = defaultRole; + } + + public void setRolePrefix(String rolePrefix) { + this.rolePrefix = rolePrefix; + } + + public void setUsernameMapper(LdapUsernameToDnMapper usernameMapper) { + this.usernameMapper = usernameMapper; + } + + public String getDefaultRole() { + return defaultRole; + } + + public void setGroupClasses(String[] groupClasses) { + this.groupClasses = groupClasses; + } +} diff --git a/org.argeo.security.core/src/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java b/org.argeo.security.core/src/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java new file mode 100644 index 000000000..e0519c37c --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java @@ -0,0 +1,622 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.security.ldap.jcr; + +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.SortedSet; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.query.Query; +import javax.jcr.version.VersionManager; +import javax.naming.Name; +import javax.naming.directory.BasicAttribute; +import javax.naming.directory.DirContext; +import javax.naming.directory.ModificationItem; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.ArgeoTypes; +import org.argeo.jcr.JcrUtils; +import org.argeo.security.SecurityUtils; +import org.argeo.security.jcr.JcrSecurityModel; +import org.argeo.security.jcr.JcrUserDetails; +import org.argeo.security.jcr.SimpleJcrSecurityModel; +import org.springframework.ldap.core.ContextMapper; +import org.springframework.ldap.core.DirContextAdapter; +import org.springframework.ldap.core.DirContextOperations; +import org.springframework.ldap.core.DistinguishedName; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.security.authentication.encoding.PasswordEncoder; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.ldap.LdapUsernameToDnMapper; +import org.springframework.security.ldap.userdetails.UserDetailsContextMapper; + +/** Makes sure that LDAP and JCR are in line. */ +public class JcrLdapSynchronizer implements UserDetailsContextMapper, + ArgeoNames { + private final static Log log = LogFactory.getLog(JcrLdapSynchronizer.class); + + // LDAP + private LdapTemplate ldapTemplate; + /** + * LDAP template whose context source has an object factory set to null. see + * this + */ + // private LdapTemplate rawLdapTemplate; + + private String userBase; + private String usernameAttribute; + private String passwordAttribute; + private String[] userClasses; + // private String defaultUserRole ="ROLE_USER"; + + // private NamingListener ldapUserListener; + // private SearchControls subTreeSearchControls; + private LdapUsernameToDnMapper usernameMapper; + + private PasswordEncoder passwordEncoder; + private final Random random; + + // JCR + /** Admin session on the main workspace */ + private Session nodeSession; + private Repository repository; + + // private JcrProfileListener jcrProfileListener; + private JcrSecurityModel jcrSecurityModel = new SimpleJcrSecurityModel(); + + // Mapping + private Map propertyToAttributes = new HashMap(); + + public JcrLdapSynchronizer() { + random = createRandom(); + } + + public void init() { + try { + nodeSession = repository.login(); + + // TODO put this in a different thread, and poll the LDAP server + // until it is up + try { + synchronize(); + + // LDAP + // subTreeSearchControls = new SearchControls(); + // subTreeSearchControls + // .setSearchScope(SearchControls.SUBTREE_SCOPE); + // LDAP listener + // ldapUserListener = new LdapUserListener(); + // rawLdapTemplate.executeReadOnly(new ContextExecutor() { + // public Object executeWithContext(DirContext ctx) + // throws NamingException { + // EventDirContext ectx = (EventDirContext) ctx.lookup(""); + // ectx.addNamingListener(userBase, "(" + // + usernameAttribute + "=*)", + // subTreeSearchControls, ldapUserListener); + // return null; + // } + // }); + } catch (Exception e) { + log.error("Could not synchronize and listen to LDAP," + + " probably because the LDAP server is not available." + + " Restart the system as soon as possible.", e); + } + + // JCR + // String[] nodeTypes = { ArgeoTypes.ARGEO_USER_PROFILE }; + // jcrProfileListener = new JcrProfileListener(); + // noLocal is used so that we are not notified when we modify JCR + // from LDAP + // nodeSession + // .getWorkspace() + // .getObservationManager() + // .addEventListener(jcrProfileListener, + // Event.PROPERTY_CHANGED | Event.NODE_ADDED, "/", + // true, null, nodeTypes, true); + } catch (Exception e) { + JcrUtils.logoutQuietly(nodeSession); + throw new ArgeoException("Cannot initialize LDAP/JCR synchronizer", + e); + } + } + + public void destroy() { + // JcrUtils.removeListenerQuietly(nodeSession, jcrProfileListener); + JcrUtils.logoutQuietly(nodeSession); + // try { + // rawLdapTemplate.executeReadOnly(new ContextExecutor() { + // public Object executeWithContext(DirContext ctx) + // throws NamingException { + // EventDirContext ectx = (EventDirContext) ctx.lookup(""); + // ectx.removeNamingListener(ldapUserListener); + // return null; + // } + // }); + // } catch (Exception e) { + // // silent (LDAP server may have been shutdown already) + // if (log.isTraceEnabled()) + // log.trace("Cannot remove LDAP listener", e); + // } + } + + /* + * LDAP TO JCR + */ + /** Full synchronization between LDAP and JCR. LDAP has priority. */ + protected void synchronize() { + try { + Name userBaseName = new DistinguishedName(userBase); + // TODO subtree search? + @SuppressWarnings("unchecked") + List userPaths = (List) ldapTemplate.listBindings( + userBaseName, new ContextMapper() { + public Object mapFromContext(Object ctxObj) { + try { + return mapLdapToJcr((DirContextAdapter) ctxObj); + } catch (Exception e) { + // do not break process because of error + log.error( + "Could not LDAP->JCR synchronize user " + + ctxObj, e); + return null; + } + } + }); + + // create accounts which are not in LDAP + Query query = nodeSession + .getWorkspace() + .getQueryManager() + .createQuery( + "select * from [" + ArgeoTypes.ARGEO_USER_PROFILE + + "]", Query.JCR_SQL2); + NodeIterator it = query.execute().getNodes(); + while (it.hasNext()) { + Node userProfile = it.nextNode(); + String path = userProfile.getPath(); + try { + if (!userPaths.contains(path)) { + String username = userProfile + .getProperty(ARGEO_USER_ID).getString(); + // GrantedAuthority[] authorities = {new + // GrantedAuthorityImpl(defaultUserRole)}; + List authorities = new ArrayList(); + JcrUserDetails userDetails = new JcrUserDetails( + userProfile, username, authorities); + String dn = createLdapUser(userDetails); + log.warn("Created ldap entry '" + dn + "' for user '" + + username + "'"); + + // if(!userProfile.getProperty(ARGEO_ENABLED).getBoolean()){ + // continue profiles; + // } + // + // log.warn("Path " + // + path + // + " not found in LDAP, disabling user " + // + userProfile.getProperty(ArgeoNames.ARGEO_USER_ID) + // .getString()); + + // Temporary hack to repair previous behaviour + if (!userProfile.getProperty(ARGEO_ENABLED) + .getBoolean()) { + VersionManager versionManager = nodeSession + .getWorkspace().getVersionManager(); + versionManager.checkout(userProfile.getPath()); + userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, + true); + nodeSession.save(); + versionManager.checkin(userProfile.getPath()); + } + } + } catch (Exception e) { + log.error("Cannot process " + path, e); + } + } + } catch (Exception e) { + JcrUtils.discardQuietly(nodeSession); + log.error("Cannot synchronize LDAP and JCR", e); + // throw new ArgeoException("Cannot synchronize LDAP and JCR", e); + } + } + + private String createLdapUser(UserDetails user) { + DirContextAdapter ctx = new DirContextAdapter(); + mapUserToContext(user, ctx); + DistinguishedName dn = usernameMapper.buildDn(user.getUsername()); + ldapTemplate.bind(dn, ctx, null); + return dn.toString(); + } + + /** Called during authentication in order to retrieve user details */ + public UserDetails mapUserFromContext(final DirContextOperations ctx, + final String username, + Collection authorities) { + if (ctx == null) + throw new ArgeoException("No LDAP information for user " + username); + + String ldapUsername = ctx.getStringAttribute(usernameAttribute); + if (!ldapUsername.equals(username)) + throw new ArgeoException("Logged in with username " + username + + " but LDAP user is " + ldapUsername); + + Node userProfile = jcrSecurityModel.sync(nodeSession, username, + SecurityUtils.authoritiesToStringList(authorities)); + // JcrUserDetails.checkAccountStatus(userProfile); + + // password + SortedSet passwordAttributes = ctx + .getAttributeSortedStringSet(passwordAttribute); + String password; + if (passwordAttributes == null || passwordAttributes.size() == 0) { + // throw new ArgeoException("No password found for user " + + // username); + password = "NULL"; + } else { + byte[] arr = (byte[]) passwordAttributes.first(); + password = new String(arr); + // erase password + Arrays.fill(arr, (byte) 0); + } + + try { + return new JcrUserDetails(userProfile, password, authorities); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot retrieve user details for " + + username, e); + } + } + + /** + * Writes an LDAP context to the JCR user profile. + * + * @return path to user profile + */ + protected synchronized String mapLdapToJcr(DirContextAdapter ctx) { + Session session = nodeSession; + try { + // process + String username = ctx.getStringAttribute(usernameAttribute); + + Node userProfile = jcrSecurityModel.sync(session, username, null); + Map modifications = new HashMap(); + for (String jcrProperty : propertyToAttributes.keySet()) + ldapToJcr(userProfile, jcrProperty, ctx, modifications); + + int modifCount = modifications.size(); + if (modifCount > 0) { + session.getWorkspace().getVersionManager() + .checkout(userProfile.getPath()); + for (String prop : modifications.keySet()) + userProfile.setProperty(prop, modifications.get(prop)); + JcrUtils.updateLastModified(userProfile); + session.save(); + session.getWorkspace().getVersionManager() + .checkin(userProfile.getPath()); + if (log.isDebugEnabled()) + log.debug("Mapped " + modifCount + " LDAP modification" + + (modifCount == 1 ? "" : "s") + " from " + + ctx.getDn() + " to " + userProfile); + } + return userProfile.getPath(); + } catch (Exception e) { + JcrUtils.discardQuietly(session); + throw new ArgeoException("Cannot synchronize JCR and LDAP", e); + } + } + + /** Maps an LDAP property to a JCR property */ + protected void ldapToJcr(Node userProfile, String jcrProperty, + DirContextOperations ctx, Map modifications) { + // TODO do we really need DirContextOperations? + try { + String ldapAttribute; + if (propertyToAttributes.containsKey(jcrProperty)) + ldapAttribute = propertyToAttributes.get(jcrProperty); + else + throw new ArgeoException( + "No LDAP attribute mapped for JCR proprty " + + jcrProperty); + + String value = ctx.getStringAttribute(ldapAttribute); + String jcrValue = userProfile.hasProperty(jcrProperty) ? userProfile + .getProperty(jcrProperty).getString() : null; + if (value != null && jcrValue != null) { + if (!value.equals(jcrValue)) + modifications.put(jcrProperty, value); + } else if (value != null && jcrValue == null) { + modifications.put(jcrProperty, value); + } else if (value == null && jcrValue != null) { + modifications.put(jcrProperty, value); + } + } catch (Exception e) { + throw new ArgeoException("Cannot map JCR property " + jcrProperty + + " from LDAP", e); + } + } + + /* + * JCR to LDAP + */ + + public void mapUserToContext(UserDetails user, final DirContextAdapter ctx) { + if (!(user instanceof JcrUserDetails)) + throw new ArgeoException("Unsupported user details: " + + user.getClass()); + + ctx.setAttributeValues("objectClass", userClasses); + ctx.setAttributeValue(usernameAttribute, user.getUsername()); + ctx.setAttributeValue(passwordAttribute, + encodePassword(user.getPassword())); + + final JcrUserDetails jcrUserDetails = (JcrUserDetails) user; + try { + Node userProfile = nodeSession + .getNode(jcrUserDetails.getHomePath()).getNode( + ARGEO_PROFILE); + for (String jcrProperty : propertyToAttributes.keySet()) { + if (userProfile.hasProperty(jcrProperty)) { + ModificationItem mi = jcrToLdap(jcrProperty, userProfile + .getProperty(jcrProperty).getString()); + if (mi != null) + ctx.setAttribute(mi.getAttribute()); + } + } + if (log.isTraceEnabled()) + log.trace("Mapped " + userProfile + " to " + ctx.getDn()); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot synchronize JCR and LDAP", e); + } + + } + + /** Maps a JCR property to an LDAP property */ + protected ModificationItem jcrToLdap(String jcrProperty, String value) { + // TODO do we really need DirContextOperations? + try { + String ldapAttribute; + if (propertyToAttributes.containsKey(jcrProperty)) + ldapAttribute = propertyToAttributes.get(jcrProperty); + else + return null; + + // fix issue with empty 'sn' in LDAP + if (ldapAttribute.equals("sn") && (value.trim().equals(""))) + return null; + // fix issue with empty 'description' in LDAP + if (ldapAttribute.equals("description") && value.trim().equals("")) + return null; + BasicAttribute attr = new BasicAttribute( + propertyToAttributes.get(jcrProperty), value); + ModificationItem mi = new ModificationItem( + DirContext.REPLACE_ATTRIBUTE, attr); + return mi; + } catch (Exception e) { + throw new ArgeoException("Cannot map JCR property " + jcrProperty + + " from LDAP", e); + } + } + + /* + * UTILITIES + */ + protected String encodePassword(String password) { + if (!password.startsWith("{")) { + byte[] salt = new byte[16]; + random.nextBytes(salt); + return passwordEncoder.encodePassword(password, salt); + } else { + return password; + } + } + + private static Random createRandom() { + try { + return SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + return new Random(System.currentTimeMillis()); + } + } + + /* + * DEPENDENCY INJECTION + */ + + public void setLdapTemplate(LdapTemplate ldapTemplate) { + this.ldapTemplate = ldapTemplate; + } + + public void setRawLdapTemplate(LdapTemplate rawLdapTemplate) { + // this.rawLdapTemplate = rawLdapTemplate; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + + public void setUserBase(String userBase) { + this.userBase = userBase; + } + + public void setUsernameAttribute(String usernameAttribute) { + this.usernameAttribute = usernameAttribute; + } + + public void setPropertyToAttributes(Map propertyToAttributes) { + this.propertyToAttributes = propertyToAttributes; + } + + public void setUsernameMapper(LdapUsernameToDnMapper usernameMapper) { + this.usernameMapper = usernameMapper; + } + + public void setPasswordAttribute(String passwordAttribute) { + this.passwordAttribute = passwordAttribute; + } + + public void setUserClasses(String[] userClasses) { + this.userClasses = userClasses; + } + + public void setPasswordEncoder(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + + public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) { + this.jcrSecurityModel = jcrSecurityModel; + } + + /** Listen to LDAP */ + // class LdapUserListener implements ObjectChangeListener, + // NamespaceChangeListener, UnsolicitedNotificationListener { + // + // public void namingExceptionThrown(NamingExceptionEvent evt) { + // evt.getException().printStackTrace(); + // } + // + // public void objectChanged(NamingEvent evt) { + // Binding user = evt.getNewBinding(); + // // TODO find a way not to be called when JCR is the source of the + // // modification + // DirContextAdapter ctx = (DirContextAdapter) ldapTemplate + // .lookup(user.getName()); + // mapLdapToJcr(ctx); + // } + // + // public void objectAdded(NamingEvent evt) { + // Binding user = evt.getNewBinding(); + // DirContextAdapter ctx = (DirContextAdapter) ldapTemplate + // .lookup(user.getName()); + // mapLdapToJcr(ctx); + // } + // + // public void objectRemoved(NamingEvent evt) { + // if (log.isDebugEnabled()) + // log.debug(evt); + // } + // + // public void objectRenamed(NamingEvent evt) { + // if (log.isDebugEnabled()) + // log.debug(evt); + // } + // + // public void notificationReceived(UnsolicitedNotificationEvent evt) { + // UnsolicitedNotification notification = evt.getNotification(); + // NamingException ne = notification.getException(); + // String msg = "LDAP notification " + "ID=" + notification.getID() + // + ", referrals=" + notification.getReferrals(); + // if (ne != null) { + // if (log.isTraceEnabled()) + // log.trace(msg + ", exception= " + ne, ne); + // else + // log.warn(msg + ", exception= " + ne); + // } else if (log.isDebugEnabled()) { + // log.debug("Unsollicited LDAP notification " + msg); + // } + // } + // + // } + + /** Listen to JCR */ + // class JcrProfileListener implements EventListener { + // + // public void onEvent(EventIterator events) { + // try { + // final Map> modifications = new HashMap>(); + // while (events.hasNext()) { + // Event event = events.nextEvent(); + // try { + // if (Event.PROPERTY_CHANGED == event.getType()) { + // Property property = (Property) nodeSession + // .getItem(event.getPath()); + // String propertyName = property.getName(); + // Node userProfile = property.getParent(); + // String username = userProfile.getProperty( + // ARGEO_USER_ID).getString(); + // if (propertyToAttributes.containsKey(propertyName)) { + // Name name = usernameMapper.buildDn(username); + // if (!modifications.containsKey(name)) + // modifications.put(name, + // new ArrayList()); + // String value = property.getString(); + // ModificationItem mi = jcrToLdap(propertyName, + // value); + // if (mi != null) + // modifications.get(name).add(mi); + // } + // } else if (Event.NODE_ADDED == event.getType()) { + // Node userProfile = nodeSession.getNode(event + // .getPath()); + // String username = userProfile.getProperty( + // ARGEO_USER_ID).getString(); + // Name name = usernameMapper.buildDn(username); + // for (String propertyName : propertyToAttributes + // .keySet()) { + // if (!modifications.containsKey(name)) + // modifications.put(name, + // new ArrayList()); + // String value = userProfile.getProperty( + // propertyName).getString(); + // ModificationItem mi = jcrToLdap(propertyName, + // value); + // if (mi != null) + // modifications.get(name).add(mi); + // } + // } + // } catch (RepositoryException e) { + // throw new ArgeoException("Cannot process event " + // + event, e); + // } + // } + // + // for (Name name : modifications.keySet()) { + // List userModifs = modifications.get(name); + // int modifCount = userModifs.size(); + // ldapTemplate.modifyAttributes(name, userModifs + // .toArray(new ModificationItem[modifCount])); + // if (log.isDebugEnabled()) + // log.debug("Mapped " + modifCount + " JCR modification" + // + (modifCount == 1 ? "" : "s") + " to " + name); + // } + // } catch (Exception e) { + // // if (log.isDebugEnabled()) + // // e.printStackTrace(); + // throw new ArgeoException("Cannot process JCR events (" + // + e.getMessage() + ")", e); + // } + // } + // + // } +} diff --git a/org.argeo.security.core/src/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java b/org.argeo.security.core/src/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java new file mode 100644 index 000000000..f63250c31 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.security.ldap.jcr; + +import java.util.Collection; +import java.util.UUID; + +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.UserJcrUtils; +import org.argeo.security.jcr.JcrUserDetails; +import org.springframework.ldap.core.DirContextAdapter; +import org.springframework.ldap.core.DirContextOperations; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.ldap.userdetails.UserDetailsContextMapper; + +/** @deprecated Read only mapping from LDAP to user details */ +@Deprecated +public class JcrUserDetailsContextMapper implements UserDetailsContextMapper, + ArgeoNames { + /** Admin session on the security workspace */ + private Session securitySession; + private Repository repository; + private String securityWorkspace = "security"; + + public void init() { + try { + securitySession = repository.login(securityWorkspace); + } catch (RepositoryException e) { + JcrUtils.logoutQuietly(securitySession); + throw new ArgeoException( + "Cannot initialize LDAP/JCR user details context mapper", e); + } + } + + public void destroy() { + JcrUtils.logoutQuietly(securitySession); + } + + /** Called during authentication in order to retrieve user details */ + public UserDetails mapUserFromContext(final DirContextOperations ctx, + final String username, + Collection authorities) { + if (ctx == null) + throw new ArgeoException("No LDAP information for user " + username); + Node userHome = UserJcrUtils.getUserHome(securitySession, username); + if (userHome == null) + throw new ArgeoException("No JCR information for user " + username); + + // password + // SortedSet passwordAttributes = ctx + // .getAttributeSortedStringSet(passwordAttribute); + // String password; + // if (passwordAttributes == null || passwordAttributes.size() == 0) { + // throw new ArgeoException("No password found for user " + username); + // } else { + // byte[] arr = (byte[]) passwordAttributes.first(); + // password = new String(arr); + // // erase password + // Arrays.fill(arr, (byte) 0); + // } + + try { + // we don't have access to password, so let's not pretend + String password = UUID.randomUUID().toString(); + return new JcrUserDetails(userHome.getNode(ARGEO_PROFILE), + password, authorities); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot retrieve user details for " + + username, e); + } + } + + public void mapUserToContext(UserDetails user, final DirContextAdapter ctx) { + throw new UnsupportedOperationException("LDAP access is read-only"); + } + +} diff --git a/org.argeo.security.jackrabbit/pom.xml b/org.argeo.security.jackrabbit/pom.xml index bb8138ff2..282c3f954 100644 --- a/org.argeo.security.jackrabbit/pom.xml +++ b/org.argeo.security.jackrabbit/pom.xml @@ -8,24 +8,12 @@ .. org.argeo.security.jackrabbit - Commons Security Jackrabbit + Commons Jackrabbit Extensions org.argeo.commons org.argeo.security.core 2.1.14-SNAPSHOT - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.security.ldap/.classpath b/org.argeo.security.ldap/.classpath deleted file mode 100644 index d2953a684..000000000 --- a/org.argeo.security.ldap/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/org.argeo.security.ldap/.project b/org.argeo.security.ldap/.project deleted file mode 100644 index 942f1404d..000000000 --- a/org.argeo.security.ldap/.project +++ /dev/null @@ -1,28 +0,0 @@ - - - org.argeo.security.ldap - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - - org.eclipse.pde.PluginNature - org.eclipse.jdt.core.javanature - - diff --git a/org.argeo.security.ldap/bnd.bnd b/org.argeo.security.ldap/bnd.bnd deleted file mode 100644 index 12f35fa05..000000000 --- a/org.argeo.security.ldap/bnd.bnd +++ /dev/null @@ -1,4 +0,0 @@ -Import-Package: org.springframework.core,\ -org.springframework.dao,\ -javax.jcr.nodetype,\ -* \ No newline at end of file diff --git a/org.argeo.security.ldap/build.properties b/org.argeo.security.ldap/build.properties deleted file mode 100644 index 30f715358..000000000 --- a/org.argeo.security.ldap/build.properties +++ /dev/null @@ -1 +0,0 @@ -source.. = src/ diff --git a/org.argeo.security.ldap/pom.xml b/org.argeo.security.ldap/pom.xml deleted file mode 100644 index 295f743d5..000000000 --- a/org.argeo.security.ldap/pom.xml +++ /dev/null @@ -1,76 +0,0 @@ - - 4.0.0 - - org.argeo.commons - argeo-commons - 2.1.14-SNAPSHOT - .. - - org.argeo.security.ldap - Commons Security LDAP - - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-source-plugin - - - org.apache.maven.plugins - maven-jar-plugin - - - org.apache.felix - maven-bundle-plugin - - - - - org.argeo.security.ldap.* - - - org.springframework.core, - org.springframework.dao, - javax.jcr.nodetype, - * - - - - - - - - - org.argeo.commons - org.argeo.util - 2.1.14-SNAPSHOT - - - org.argeo.commons - org.argeo.security.core - 2.1.14-SNAPSHOT - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.security.ldap/src/org/argeo/security/ldap/ArgeoLdapShaPasswordEncoder.java b/org.argeo.security.ldap/src/org/argeo/security/ldap/ArgeoLdapShaPasswordEncoder.java deleted file mode 100644 index a2c43a589..000000000 --- a/org.argeo.security.ldap/src/org/argeo/security/ldap/ArgeoLdapShaPasswordEncoder.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.security.ldap; - -import org.springframework.security.authentication.encoding.LdapShaPasswordEncoder; - -/** - * {@link LdapShaPasswordEncoder} allowing to configure the usage of salt (APache - * Directory Server 1.0 does not support bind with SSHA) - */ -public class ArgeoLdapShaPasswordEncoder extends LdapShaPasswordEncoder { - private Boolean useSalt = true; - - @Override - public String encodePassword(String rawPass, Object salt) { - return super.encodePassword(rawPass, useSalt ? salt : null); - } - - public void setUseSalt(Boolean useSalt) { - this.useSalt = useSalt; - } - -} diff --git a/org.argeo.security.ldap/src/org/argeo/security/ldap/ArgeoLdapUserDetailsManager.java b/org.argeo.security.ldap/src/org/argeo/security/ldap/ArgeoLdapUserDetailsManager.java deleted file mode 100644 index 89b5aa92d..000000000 --- a/org.argeo.security.ldap/src/org/argeo/security/ldap/ArgeoLdapUserDetailsManager.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.security.ldap; - -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.TreeSet; - -import org.argeo.ArgeoException; -import org.argeo.security.UserAdminService; -import org.springframework.ldap.core.ContextSource; -import org.springframework.security.authentication.encoding.PasswordEncoder; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.ldap.userdetails.LdapUserDetailsManager; - -/** Extends {@link LdapUserDetailsManager} by adding password encoding support. */ -public class ArgeoLdapUserDetailsManager extends LdapUserDetailsManager - implements UserAdminService { - private String superUsername = "root"; - private ArgeoUserAdminDaoLdap userAdminDao; - private PasswordEncoder passwordEncoder; - private final Random random; - - public ArgeoLdapUserDetailsManager(ContextSource contextSource) { - super(contextSource); - this.random = createRandom(); - } - - private static Random createRandom() { - try { - return SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - return new Random(System.currentTimeMillis()); - } - } - - @Override - public void changePassword(String oldPassword, String newPassword) { - Authentication authentication = SecurityContextHolder.getContext() - .getAuthentication(); - if (authentication == null) - throw new ArgeoException( - "Cannot change password without authentication"); - String username = authentication.getName(); - UserDetails userDetails = loadUserByUsername(username); - String currentPassword = userDetails.getPassword(); - if (currentPassword == null) - throw new ArgeoException("Cannot access current password"); - if (!passwordEncoder - .isPasswordValid(currentPassword, oldPassword, null)) - throw new ArgeoException("Old password invalid"); - // Spring Security LDAP 2.0 is buggy when used with OpenLDAP and called - // with oldPassword argument - super.changePassword(null, encodePassword(newPassword)); - } - - public void newRole(String role) { - userAdminDao.createRole(role, superUsername); - } - - public void synchronize() { - for (String username : userAdminDao.listUsers()) - loadUserByUsername(username); - // TODO: find a way to remove from JCR - } - - public void deleteRole(String role) { - userAdminDao.deleteRole(role); - } - - public Set listUsers() { - return userAdminDao.listUsers(); - } - - public Set listUsersInRole(String role) { - Set lst = new TreeSet( - userAdminDao.listUsersInRole(role)); - Iterator it = lst.iterator(); - while (it.hasNext()) { - if (it.next().equals(superUsername)) { - it.remove(); - break; - } - } - return lst; - } - - public List listUserRoles(String username) { - UserDetails userDetails = loadUserByUsername(username); - List roles = new ArrayList(); - for (GrantedAuthority ga : userDetails.getAuthorities()) { - roles.add(ga.getAuthority()); - } - return Collections.unmodifiableList(roles); - } - - public Set listEditableRoles() { - return userAdminDao.listEditableRoles(); - } - - protected String encodePassword(String password) { - if (!password.startsWith("{")) { - byte[] salt = new byte[16]; - random.nextBytes(salt); - return passwordEncoder.encodePassword(password, salt); - } else { - return password; - } - } - - public void setPasswordEncoder(PasswordEncoder passwordEncoder) { - this.passwordEncoder = passwordEncoder; - } - - public void setSuperUsername(String superUsername) { - this.superUsername = superUsername; - } - - public void setUserAdminDao(ArgeoUserAdminDaoLdap userAdminDao) { - this.userAdminDao = userAdminDao; - } - -} diff --git a/org.argeo.security.ldap/src/org/argeo/security/ldap/ArgeoUserAdminDaoLdap.java b/org.argeo.security.ldap/src/org/argeo/security/ldap/ArgeoUserAdminDaoLdap.java deleted file mode 100644 index 37d2a06a0..000000000 --- a/org.argeo.security.ldap/src/org/argeo/security/ldap/ArgeoUserAdminDaoLdap.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.security.ldap; - -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; - -import javax.naming.Name; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; - -import org.springframework.ldap.core.ContextExecutor; -import org.springframework.ldap.core.ContextMapper; -import org.springframework.ldap.core.DirContextAdapter; -import org.springframework.ldap.core.DistinguishedName; -import org.springframework.ldap.core.LdapTemplate; -import org.springframework.ldap.core.support.BaseLdapPathContextSource; -import org.springframework.security.ldap.LdapUsernameToDnMapper; -import org.springframework.security.ldap.LdapUtils; - -/** - * Wraps low-level LDAP operation on user and roles, used by - * {@link ArgeoLdapUserDetailsManager} - */ -public class ArgeoUserAdminDaoLdap { - private String userBase; - private String usernameAttribute; - private String groupBase; - private String[] groupClasses; - - private String groupRoleAttribute; - private String groupMemberAttribute; - private String defaultRole; - private String rolePrefix; - - private final LdapTemplate ldapTemplate; - private LdapUsernameToDnMapper usernameMapper; - - /** - * Standard constructor, using the LDAP context source shared with Spring - * Security components. - */ - public ArgeoUserAdminDaoLdap(BaseLdapPathContextSource contextSource) { - this.ldapTemplate = new LdapTemplate(contextSource); - } - - @SuppressWarnings("unchecked") - public synchronized Set listUsers() { - List usernames = (List) ldapTemplate.listBindings( - new DistinguishedName(userBase), new ContextMapper() { - public Object mapFromContext(Object ctxArg) { - DirContextAdapter ctx = (DirContextAdapter) ctxArg; - return ctx.getStringAttribute(usernameAttribute); - } - }); - - return Collections - .unmodifiableSortedSet(new TreeSet(usernames)); - } - - @SuppressWarnings("unchecked") - public Set listEditableRoles() { - return Collections.unmodifiableSortedSet(new TreeSet( - ldapTemplate.listBindings(groupBase, new ContextMapper() { - public Object mapFromContext(Object ctxArg) { - String groupName = ((DirContextAdapter) ctxArg) - .getStringAttribute(groupRoleAttribute); - String roleName = convertGroupToRole(groupName); - return roleName; - } - }))); - } - - @SuppressWarnings("unchecked") - public Set listUsersInRole(String role) { - return (Set) ldapTemplate.lookup( - buildGroupDn(convertRoleToGroup(role)), new ContextMapper() { - public Object mapFromContext(Object ctxArg) { - DirContextAdapter ctx = (DirContextAdapter) ctxArg; - String[] userDns = ctx - .getStringAttributes(groupMemberAttribute); - TreeSet set = new TreeSet(); - for (String userDn : userDns) { - DistinguishedName dn = new DistinguishedName(userDn); - String username = dn.getValue(usernameAttribute); - set.add(username); - } - return Collections.unmodifiableSortedSet(set); - } - }); - } - - public void createRole(String role, final String superuserName) { - String group = convertRoleToGroup(role); - DistinguishedName superuserDn = (DistinguishedName) ldapTemplate - .executeReadWrite(new ContextExecutor() { - public Object executeWithContext(DirContext ctx) - throws NamingException { - return LdapUtils.getFullDn( - usernameMapper.buildDn(superuserName), ctx); - } - }); - - Name groupDn = buildGroupDn(group); - DirContextAdapter context = new DirContextAdapter(); - context.setAttributeValues("objectClass", groupClasses); - context.setAttributeValue("cn", group); - // Add superuser because cannot create empty group - context.setAttributeValue(groupMemberAttribute, superuserDn.toString()); - ldapTemplate.bind(groupDn, context, null); - } - - public void deleteRole(String role) { - String group = convertRoleToGroup(role); - Name dn = buildGroupDn(group); - ldapTemplate.unbind(dn); - } - - /** Maps a role (ROLE_XXX) to the related LDAP group (xxx) */ - protected String convertRoleToGroup(String role) { - String group = role; - if (group.startsWith(rolePrefix)) { - group = group.substring(rolePrefix.length()); - group = group.toLowerCase(); - } - return group; - } - - /** Maps anLDAP group (xxx) to the related role (ROLE_XXX) */ - protected String convertGroupToRole(String groupName) { - groupName = groupName.toUpperCase(); - - return rolePrefix + groupName; - } - - protected Name buildGroupDn(String name) { - return new DistinguishedName(groupRoleAttribute + "=" + name + "," - + groupBase); - } - - public void setUserBase(String userBase) { - this.userBase = userBase; - } - - public void setUsernameAttribute(String usernameAttribute) { - this.usernameAttribute = usernameAttribute; - } - - public void setGroupBase(String groupBase) { - this.groupBase = groupBase; - } - - public void setGroupRoleAttribute(String groupRoleAttributeName) { - this.groupRoleAttribute = groupRoleAttributeName; - } - - public void setGroupMemberAttribute(String groupMemberAttributeName) { - this.groupMemberAttribute = groupMemberAttributeName; - } - - public void setDefaultRole(String defaultRole) { - this.defaultRole = defaultRole; - } - - public void setRolePrefix(String rolePrefix) { - this.rolePrefix = rolePrefix; - } - - public void setUsernameMapper(LdapUsernameToDnMapper usernameMapper) { - this.usernameMapper = usernameMapper; - } - - public String getDefaultRole() { - return defaultRole; - } - - public void setGroupClasses(String[] groupClasses) { - this.groupClasses = groupClasses; - } -} diff --git a/org.argeo.security.ldap/src/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java b/org.argeo.security.ldap/src/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java deleted file mode 100644 index e0519c37c..000000000 --- a/org.argeo.security.ldap/src/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java +++ /dev/null @@ -1,622 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.security.ldap.jcr; - -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.SortedSet; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.query.Query; -import javax.jcr.version.VersionManager; -import javax.naming.Name; -import javax.naming.directory.BasicAttribute; -import javax.naming.directory.DirContext; -import javax.naming.directory.ModificationItem; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.ArgeoTypes; -import org.argeo.jcr.JcrUtils; -import org.argeo.security.SecurityUtils; -import org.argeo.security.jcr.JcrSecurityModel; -import org.argeo.security.jcr.JcrUserDetails; -import org.argeo.security.jcr.SimpleJcrSecurityModel; -import org.springframework.ldap.core.ContextMapper; -import org.springframework.ldap.core.DirContextAdapter; -import org.springframework.ldap.core.DirContextOperations; -import org.springframework.ldap.core.DistinguishedName; -import org.springframework.ldap.core.LdapTemplate; -import org.springframework.security.authentication.encoding.PasswordEncoder; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.ldap.LdapUsernameToDnMapper; -import org.springframework.security.ldap.userdetails.UserDetailsContextMapper; - -/** Makes sure that LDAP and JCR are in line. */ -public class JcrLdapSynchronizer implements UserDetailsContextMapper, - ArgeoNames { - private final static Log log = LogFactory.getLog(JcrLdapSynchronizer.class); - - // LDAP - private LdapTemplate ldapTemplate; - /** - * LDAP template whose context source has an object factory set to null. see - * this - */ - // private LdapTemplate rawLdapTemplate; - - private String userBase; - private String usernameAttribute; - private String passwordAttribute; - private String[] userClasses; - // private String defaultUserRole ="ROLE_USER"; - - // private NamingListener ldapUserListener; - // private SearchControls subTreeSearchControls; - private LdapUsernameToDnMapper usernameMapper; - - private PasswordEncoder passwordEncoder; - private final Random random; - - // JCR - /** Admin session on the main workspace */ - private Session nodeSession; - private Repository repository; - - // private JcrProfileListener jcrProfileListener; - private JcrSecurityModel jcrSecurityModel = new SimpleJcrSecurityModel(); - - // Mapping - private Map propertyToAttributes = new HashMap(); - - public JcrLdapSynchronizer() { - random = createRandom(); - } - - public void init() { - try { - nodeSession = repository.login(); - - // TODO put this in a different thread, and poll the LDAP server - // until it is up - try { - synchronize(); - - // LDAP - // subTreeSearchControls = new SearchControls(); - // subTreeSearchControls - // .setSearchScope(SearchControls.SUBTREE_SCOPE); - // LDAP listener - // ldapUserListener = new LdapUserListener(); - // rawLdapTemplate.executeReadOnly(new ContextExecutor() { - // public Object executeWithContext(DirContext ctx) - // throws NamingException { - // EventDirContext ectx = (EventDirContext) ctx.lookup(""); - // ectx.addNamingListener(userBase, "(" - // + usernameAttribute + "=*)", - // subTreeSearchControls, ldapUserListener); - // return null; - // } - // }); - } catch (Exception e) { - log.error("Could not synchronize and listen to LDAP," - + " probably because the LDAP server is not available." - + " Restart the system as soon as possible.", e); - } - - // JCR - // String[] nodeTypes = { ArgeoTypes.ARGEO_USER_PROFILE }; - // jcrProfileListener = new JcrProfileListener(); - // noLocal is used so that we are not notified when we modify JCR - // from LDAP - // nodeSession - // .getWorkspace() - // .getObservationManager() - // .addEventListener(jcrProfileListener, - // Event.PROPERTY_CHANGED | Event.NODE_ADDED, "/", - // true, null, nodeTypes, true); - } catch (Exception e) { - JcrUtils.logoutQuietly(nodeSession); - throw new ArgeoException("Cannot initialize LDAP/JCR synchronizer", - e); - } - } - - public void destroy() { - // JcrUtils.removeListenerQuietly(nodeSession, jcrProfileListener); - JcrUtils.logoutQuietly(nodeSession); - // try { - // rawLdapTemplate.executeReadOnly(new ContextExecutor() { - // public Object executeWithContext(DirContext ctx) - // throws NamingException { - // EventDirContext ectx = (EventDirContext) ctx.lookup(""); - // ectx.removeNamingListener(ldapUserListener); - // return null; - // } - // }); - // } catch (Exception e) { - // // silent (LDAP server may have been shutdown already) - // if (log.isTraceEnabled()) - // log.trace("Cannot remove LDAP listener", e); - // } - } - - /* - * LDAP TO JCR - */ - /** Full synchronization between LDAP and JCR. LDAP has priority. */ - protected void synchronize() { - try { - Name userBaseName = new DistinguishedName(userBase); - // TODO subtree search? - @SuppressWarnings("unchecked") - List userPaths = (List) ldapTemplate.listBindings( - userBaseName, new ContextMapper() { - public Object mapFromContext(Object ctxObj) { - try { - return mapLdapToJcr((DirContextAdapter) ctxObj); - } catch (Exception e) { - // do not break process because of error - log.error( - "Could not LDAP->JCR synchronize user " - + ctxObj, e); - return null; - } - } - }); - - // create accounts which are not in LDAP - Query query = nodeSession - .getWorkspace() - .getQueryManager() - .createQuery( - "select * from [" + ArgeoTypes.ARGEO_USER_PROFILE - + "]", Query.JCR_SQL2); - NodeIterator it = query.execute().getNodes(); - while (it.hasNext()) { - Node userProfile = it.nextNode(); - String path = userProfile.getPath(); - try { - if (!userPaths.contains(path)) { - String username = userProfile - .getProperty(ARGEO_USER_ID).getString(); - // GrantedAuthority[] authorities = {new - // GrantedAuthorityImpl(defaultUserRole)}; - List authorities = new ArrayList(); - JcrUserDetails userDetails = new JcrUserDetails( - userProfile, username, authorities); - String dn = createLdapUser(userDetails); - log.warn("Created ldap entry '" + dn + "' for user '" - + username + "'"); - - // if(!userProfile.getProperty(ARGEO_ENABLED).getBoolean()){ - // continue profiles; - // } - // - // log.warn("Path " - // + path - // + " not found in LDAP, disabling user " - // + userProfile.getProperty(ArgeoNames.ARGEO_USER_ID) - // .getString()); - - // Temporary hack to repair previous behaviour - if (!userProfile.getProperty(ARGEO_ENABLED) - .getBoolean()) { - VersionManager versionManager = nodeSession - .getWorkspace().getVersionManager(); - versionManager.checkout(userProfile.getPath()); - userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, - true); - nodeSession.save(); - versionManager.checkin(userProfile.getPath()); - } - } - } catch (Exception e) { - log.error("Cannot process " + path, e); - } - } - } catch (Exception e) { - JcrUtils.discardQuietly(nodeSession); - log.error("Cannot synchronize LDAP and JCR", e); - // throw new ArgeoException("Cannot synchronize LDAP and JCR", e); - } - } - - private String createLdapUser(UserDetails user) { - DirContextAdapter ctx = new DirContextAdapter(); - mapUserToContext(user, ctx); - DistinguishedName dn = usernameMapper.buildDn(user.getUsername()); - ldapTemplate.bind(dn, ctx, null); - return dn.toString(); - } - - /** Called during authentication in order to retrieve user details */ - public UserDetails mapUserFromContext(final DirContextOperations ctx, - final String username, - Collection authorities) { - if (ctx == null) - throw new ArgeoException("No LDAP information for user " + username); - - String ldapUsername = ctx.getStringAttribute(usernameAttribute); - if (!ldapUsername.equals(username)) - throw new ArgeoException("Logged in with username " + username - + " but LDAP user is " + ldapUsername); - - Node userProfile = jcrSecurityModel.sync(nodeSession, username, - SecurityUtils.authoritiesToStringList(authorities)); - // JcrUserDetails.checkAccountStatus(userProfile); - - // password - SortedSet passwordAttributes = ctx - .getAttributeSortedStringSet(passwordAttribute); - String password; - if (passwordAttributes == null || passwordAttributes.size() == 0) { - // throw new ArgeoException("No password found for user " + - // username); - password = "NULL"; - } else { - byte[] arr = (byte[]) passwordAttributes.first(); - password = new String(arr); - // erase password - Arrays.fill(arr, (byte) 0); - } - - try { - return new JcrUserDetails(userProfile, password, authorities); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot retrieve user details for " - + username, e); - } - } - - /** - * Writes an LDAP context to the JCR user profile. - * - * @return path to user profile - */ - protected synchronized String mapLdapToJcr(DirContextAdapter ctx) { - Session session = nodeSession; - try { - // process - String username = ctx.getStringAttribute(usernameAttribute); - - Node userProfile = jcrSecurityModel.sync(session, username, null); - Map modifications = new HashMap(); - for (String jcrProperty : propertyToAttributes.keySet()) - ldapToJcr(userProfile, jcrProperty, ctx, modifications); - - int modifCount = modifications.size(); - if (modifCount > 0) { - session.getWorkspace().getVersionManager() - .checkout(userProfile.getPath()); - for (String prop : modifications.keySet()) - userProfile.setProperty(prop, modifications.get(prop)); - JcrUtils.updateLastModified(userProfile); - session.save(); - session.getWorkspace().getVersionManager() - .checkin(userProfile.getPath()); - if (log.isDebugEnabled()) - log.debug("Mapped " + modifCount + " LDAP modification" - + (modifCount == 1 ? "" : "s") + " from " - + ctx.getDn() + " to " + userProfile); - } - return userProfile.getPath(); - } catch (Exception e) { - JcrUtils.discardQuietly(session); - throw new ArgeoException("Cannot synchronize JCR and LDAP", e); - } - } - - /** Maps an LDAP property to a JCR property */ - protected void ldapToJcr(Node userProfile, String jcrProperty, - DirContextOperations ctx, Map modifications) { - // TODO do we really need DirContextOperations? - try { - String ldapAttribute; - if (propertyToAttributes.containsKey(jcrProperty)) - ldapAttribute = propertyToAttributes.get(jcrProperty); - else - throw new ArgeoException( - "No LDAP attribute mapped for JCR proprty " - + jcrProperty); - - String value = ctx.getStringAttribute(ldapAttribute); - String jcrValue = userProfile.hasProperty(jcrProperty) ? userProfile - .getProperty(jcrProperty).getString() : null; - if (value != null && jcrValue != null) { - if (!value.equals(jcrValue)) - modifications.put(jcrProperty, value); - } else if (value != null && jcrValue == null) { - modifications.put(jcrProperty, value); - } else if (value == null && jcrValue != null) { - modifications.put(jcrProperty, value); - } - } catch (Exception e) { - throw new ArgeoException("Cannot map JCR property " + jcrProperty - + " from LDAP", e); - } - } - - /* - * JCR to LDAP - */ - - public void mapUserToContext(UserDetails user, final DirContextAdapter ctx) { - if (!(user instanceof JcrUserDetails)) - throw new ArgeoException("Unsupported user details: " - + user.getClass()); - - ctx.setAttributeValues("objectClass", userClasses); - ctx.setAttributeValue(usernameAttribute, user.getUsername()); - ctx.setAttributeValue(passwordAttribute, - encodePassword(user.getPassword())); - - final JcrUserDetails jcrUserDetails = (JcrUserDetails) user; - try { - Node userProfile = nodeSession - .getNode(jcrUserDetails.getHomePath()).getNode( - ARGEO_PROFILE); - for (String jcrProperty : propertyToAttributes.keySet()) { - if (userProfile.hasProperty(jcrProperty)) { - ModificationItem mi = jcrToLdap(jcrProperty, userProfile - .getProperty(jcrProperty).getString()); - if (mi != null) - ctx.setAttribute(mi.getAttribute()); - } - } - if (log.isTraceEnabled()) - log.trace("Mapped " + userProfile + " to " + ctx.getDn()); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot synchronize JCR and LDAP", e); - } - - } - - /** Maps a JCR property to an LDAP property */ - protected ModificationItem jcrToLdap(String jcrProperty, String value) { - // TODO do we really need DirContextOperations? - try { - String ldapAttribute; - if (propertyToAttributes.containsKey(jcrProperty)) - ldapAttribute = propertyToAttributes.get(jcrProperty); - else - return null; - - // fix issue with empty 'sn' in LDAP - if (ldapAttribute.equals("sn") && (value.trim().equals(""))) - return null; - // fix issue with empty 'description' in LDAP - if (ldapAttribute.equals("description") && value.trim().equals("")) - return null; - BasicAttribute attr = new BasicAttribute( - propertyToAttributes.get(jcrProperty), value); - ModificationItem mi = new ModificationItem( - DirContext.REPLACE_ATTRIBUTE, attr); - return mi; - } catch (Exception e) { - throw new ArgeoException("Cannot map JCR property " + jcrProperty - + " from LDAP", e); - } - } - - /* - * UTILITIES - */ - protected String encodePassword(String password) { - if (!password.startsWith("{")) { - byte[] salt = new byte[16]; - random.nextBytes(salt); - return passwordEncoder.encodePassword(password, salt); - } else { - return password; - } - } - - private static Random createRandom() { - try { - return SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - return new Random(System.currentTimeMillis()); - } - } - - /* - * DEPENDENCY INJECTION - */ - - public void setLdapTemplate(LdapTemplate ldapTemplate) { - this.ldapTemplate = ldapTemplate; - } - - public void setRawLdapTemplate(LdapTemplate rawLdapTemplate) { - // this.rawLdapTemplate = rawLdapTemplate; - } - - public void setRepository(Repository repository) { - this.repository = repository; - } - - public void setUserBase(String userBase) { - this.userBase = userBase; - } - - public void setUsernameAttribute(String usernameAttribute) { - this.usernameAttribute = usernameAttribute; - } - - public void setPropertyToAttributes(Map propertyToAttributes) { - this.propertyToAttributes = propertyToAttributes; - } - - public void setUsernameMapper(LdapUsernameToDnMapper usernameMapper) { - this.usernameMapper = usernameMapper; - } - - public void setPasswordAttribute(String passwordAttribute) { - this.passwordAttribute = passwordAttribute; - } - - public void setUserClasses(String[] userClasses) { - this.userClasses = userClasses; - } - - public void setPasswordEncoder(PasswordEncoder passwordEncoder) { - this.passwordEncoder = passwordEncoder; - } - - public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) { - this.jcrSecurityModel = jcrSecurityModel; - } - - /** Listen to LDAP */ - // class LdapUserListener implements ObjectChangeListener, - // NamespaceChangeListener, UnsolicitedNotificationListener { - // - // public void namingExceptionThrown(NamingExceptionEvent evt) { - // evt.getException().printStackTrace(); - // } - // - // public void objectChanged(NamingEvent evt) { - // Binding user = evt.getNewBinding(); - // // TODO find a way not to be called when JCR is the source of the - // // modification - // DirContextAdapter ctx = (DirContextAdapter) ldapTemplate - // .lookup(user.getName()); - // mapLdapToJcr(ctx); - // } - // - // public void objectAdded(NamingEvent evt) { - // Binding user = evt.getNewBinding(); - // DirContextAdapter ctx = (DirContextAdapter) ldapTemplate - // .lookup(user.getName()); - // mapLdapToJcr(ctx); - // } - // - // public void objectRemoved(NamingEvent evt) { - // if (log.isDebugEnabled()) - // log.debug(evt); - // } - // - // public void objectRenamed(NamingEvent evt) { - // if (log.isDebugEnabled()) - // log.debug(evt); - // } - // - // public void notificationReceived(UnsolicitedNotificationEvent evt) { - // UnsolicitedNotification notification = evt.getNotification(); - // NamingException ne = notification.getException(); - // String msg = "LDAP notification " + "ID=" + notification.getID() - // + ", referrals=" + notification.getReferrals(); - // if (ne != null) { - // if (log.isTraceEnabled()) - // log.trace(msg + ", exception= " + ne, ne); - // else - // log.warn(msg + ", exception= " + ne); - // } else if (log.isDebugEnabled()) { - // log.debug("Unsollicited LDAP notification " + msg); - // } - // } - // - // } - - /** Listen to JCR */ - // class JcrProfileListener implements EventListener { - // - // public void onEvent(EventIterator events) { - // try { - // final Map> modifications = new HashMap>(); - // while (events.hasNext()) { - // Event event = events.nextEvent(); - // try { - // if (Event.PROPERTY_CHANGED == event.getType()) { - // Property property = (Property) nodeSession - // .getItem(event.getPath()); - // String propertyName = property.getName(); - // Node userProfile = property.getParent(); - // String username = userProfile.getProperty( - // ARGEO_USER_ID).getString(); - // if (propertyToAttributes.containsKey(propertyName)) { - // Name name = usernameMapper.buildDn(username); - // if (!modifications.containsKey(name)) - // modifications.put(name, - // new ArrayList()); - // String value = property.getString(); - // ModificationItem mi = jcrToLdap(propertyName, - // value); - // if (mi != null) - // modifications.get(name).add(mi); - // } - // } else if (Event.NODE_ADDED == event.getType()) { - // Node userProfile = nodeSession.getNode(event - // .getPath()); - // String username = userProfile.getProperty( - // ARGEO_USER_ID).getString(); - // Name name = usernameMapper.buildDn(username); - // for (String propertyName : propertyToAttributes - // .keySet()) { - // if (!modifications.containsKey(name)) - // modifications.put(name, - // new ArrayList()); - // String value = userProfile.getProperty( - // propertyName).getString(); - // ModificationItem mi = jcrToLdap(propertyName, - // value); - // if (mi != null) - // modifications.get(name).add(mi); - // } - // } - // } catch (RepositoryException e) { - // throw new ArgeoException("Cannot process event " - // + event, e); - // } - // } - // - // for (Name name : modifications.keySet()) { - // List userModifs = modifications.get(name); - // int modifCount = userModifs.size(); - // ldapTemplate.modifyAttributes(name, userModifs - // .toArray(new ModificationItem[modifCount])); - // if (log.isDebugEnabled()) - // log.debug("Mapped " + modifCount + " JCR modification" - // + (modifCount == 1 ? "" : "s") + " to " + name); - // } - // } catch (Exception e) { - // // if (log.isDebugEnabled()) - // // e.printStackTrace(); - // throw new ArgeoException("Cannot process JCR events (" - // + e.getMessage() + ")", e); - // } - // } - // - // } -} diff --git a/org.argeo.security.ldap/src/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java b/org.argeo.security.ldap/src/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java deleted file mode 100644 index f63250c31..000000000 --- a/org.argeo.security.ldap/src/org/argeo/security/ldap/jcr/JcrUserDetailsContextMapper.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.security.ldap.jcr; - -import java.util.Collection; -import java.util.UUID; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.UserJcrUtils; -import org.argeo.security.jcr.JcrUserDetails; -import org.springframework.ldap.core.DirContextAdapter; -import org.springframework.ldap.core.DirContextOperations; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.ldap.userdetails.UserDetailsContextMapper; - -/** @deprecated Read only mapping from LDAP to user details */ -@Deprecated -public class JcrUserDetailsContextMapper implements UserDetailsContextMapper, - ArgeoNames { - /** Admin session on the security workspace */ - private Session securitySession; - private Repository repository; - private String securityWorkspace = "security"; - - public void init() { - try { - securitySession = repository.login(securityWorkspace); - } catch (RepositoryException e) { - JcrUtils.logoutQuietly(securitySession); - throw new ArgeoException( - "Cannot initialize LDAP/JCR user details context mapper", e); - } - } - - public void destroy() { - JcrUtils.logoutQuietly(securitySession); - } - - /** Called during authentication in order to retrieve user details */ - public UserDetails mapUserFromContext(final DirContextOperations ctx, - final String username, - Collection authorities) { - if (ctx == null) - throw new ArgeoException("No LDAP information for user " + username); - Node userHome = UserJcrUtils.getUserHome(securitySession, username); - if (userHome == null) - throw new ArgeoException("No JCR information for user " + username); - - // password - // SortedSet passwordAttributes = ctx - // .getAttributeSortedStringSet(passwordAttribute); - // String password; - // if (passwordAttributes == null || passwordAttributes.size() == 0) { - // throw new ArgeoException("No password found for user " + username); - // } else { - // byte[] arr = (byte[]) passwordAttributes.first(); - // password = new String(arr); - // // erase password - // Arrays.fill(arr, (byte) 0); - // } - - try { - // we don't have access to password, so let's not pretend - String password = UUID.randomUUID().toString(); - return new JcrUserDetails(userHome.getNode(ARGEO_PROFILE), - password, authorities); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot retrieve user details for " - + username, e); - } - } - - public void mapUserToContext(UserDetails user, final DirContextAdapter ctx) { - throw new UnsupportedOperationException("LDAP access is read-only"); - } - -} diff --git a/org.argeo.security.ui.admin/pom.xml b/org.argeo.security.ui.admin/pom.xml index e11b5b4a3..cd153c903 100644 --- a/org.argeo.security.ui.admin/pom.xml +++ b/org.argeo.security.ui.admin/pom.xml @@ -8,59 +8,34 @@ .. org.argeo.security.ui.admin - Commons Security Admin UI + Commons CMS Workbench Admin jar - org.argeo.commons - org.argeo.security.ui + org.argeo.util 2.1.14-SNAPSHOT org.argeo.commons - org.argeo.security.core + org.argeo.security.ui 2.1.14-SNAPSHOT - - org.argeo.commons - org.argeo.eclipse.ui.rap + org.argeo.security.core 2.1.14-SNAPSHOT - provided - org.argeo.commons org.argeo.eclipse.ui 2.1.14-SNAPSHOT - - org.argeo.commons - org.argeo.util + org.argeo.eclipse.ui.rap 2.1.14-SNAPSHOT + provided - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.security.ui.rap/pom.xml b/org.argeo.security.ui.rap/pom.xml index 6aa33e871..208cd173e 100644 --- a/org.argeo.security.ui.rap/pom.xml +++ b/org.argeo.security.ui.rap/pom.xml @@ -8,37 +8,19 @@ .. org.argeo.security.ui.rap - Commons Security UI RAP + Commons CMS Workbench RAP jar - org.argeo.commons org.argeo.util 2.1.14-SNAPSHOT - - - - - - - - org.argeo.commons org.argeo.security.ui 2.1.14-SNAPSHOT - - - - - - - - org.argeo.commons org.argeo.eclipse.ui.rap diff --git a/org.argeo.security.ui/pom.xml b/org.argeo.security.ui/pom.xml index 5634891ab..14b240165 100644 --- a/org.argeo.security.ui/pom.xml +++ b/org.argeo.security.ui/pom.xml @@ -8,45 +8,23 @@ .. org.argeo.security.ui - Commons Security UI + Commons CMS Workbench jar - org.argeo.commons org.argeo.security.core 2.1.14-SNAPSHOT - - org.argeo.commons org.argeo.eclipse.ui.workbench 2.1.14-SNAPSHOT - - - - - org.argeo.commons org.argeo.util 2.1.14-SNAPSHOT - - - - - - - - \ No newline at end of file diff --git a/org.argeo.server.core/.classpath b/org.argeo.server.core/.classpath deleted file mode 100644 index d2953a684..000000000 --- a/org.argeo.server.core/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/org.argeo.server.core/.project b/org.argeo.server.core/.project deleted file mode 100644 index b28214ba7..000000000 --- a/org.argeo.server.core/.project +++ /dev/null @@ -1,28 +0,0 @@ - - - org.argeo.server.core - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.pde.PluginNature - - diff --git a/org.argeo.server.core/bnd.bnd b/org.argeo.server.core/bnd.bnd deleted file mode 100644 index 8a56d16ed..000000000 --- a/org.argeo.server.core/bnd.bnd +++ /dev/null @@ -1,3 +0,0 @@ -Import-Package: javax.servlet,\ -org.springframework.web.context,\ -* \ No newline at end of file diff --git a/org.argeo.server.core/build.properties b/org.argeo.server.core/build.properties deleted file mode 100644 index 63f6b336e..000000000 --- a/org.argeo.server.core/build.properties +++ /dev/null @@ -1,4 +0,0 @@ -source.. = src/ -additional.bundles = org.apache.log4j,\ - com.jcraft.jsch - \ No newline at end of file diff --git a/org.argeo.server.core/pom.xml b/org.argeo.server.core/pom.xml deleted file mode 100644 index 9d81e2e97..000000000 --- a/org.argeo.server.core/pom.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - 4.0.0 - - org.argeo.commons - argeo-commons - 2.1.14-SNAPSHOT - .. - - org.argeo.server.core - Commons Server Core - - - org.argeo.commons - org.argeo.util - 2.1.14-SNAPSHOT - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.server.core/src/org/argeo/server/BooleanAnswer.java b/org.argeo.server.core/src/org/argeo/server/BooleanAnswer.java deleted file mode 100644 index 2b7ffb2fc..000000000 --- a/org.argeo.server.core/src/org/argeo/server/BooleanAnswer.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server; - - -/** Answer to an execution of a remote service which performed changes. */ -public class BooleanAnswer { - private Boolean value = Boolean.TRUE; - - /** Canonical constructor */ - public BooleanAnswer(Boolean status) { - this.value = status; - } - - /** Empty constructor */ - public BooleanAnswer() { - } - - public Boolean getValue() { - return value; - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/Deserializer.java b/org.argeo.server.core/src/org/argeo/server/Deserializer.java deleted file mode 100644 index 4d7faf966..000000000 --- a/org.argeo.server.core/src/org/argeo/server/Deserializer.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server; - -import java.io.Reader; - -public interface Deserializer { - public T deserialize(Reader reader, Class clss); -} diff --git a/org.argeo.server.core/src/org/argeo/server/DeserializingEditor.java b/org.argeo.server.core/src/org/argeo/server/DeserializingEditor.java deleted file mode 100644 index 915b71cfe..000000000 --- a/org.argeo.server.core/src/org/argeo/server/DeserializingEditor.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server; - -import java.beans.PropertyEditorSupport; -import java.io.StringReader; - -import org.apache.commons.io.IOUtils; - -public class DeserializingEditor extends PropertyEditorSupport { - private final Deserializer deserializer; - private final Class targetClass; - - public DeserializingEditor(Deserializer deserializer, Class targetClass) { - super(); - this.deserializer = deserializer; - this.targetClass = targetClass; - } - - @Override - public void setAsText(String text) throws IllegalArgumentException { - StringReader reader = new StringReader(text); - try { - setValue(deserializer.deserialize(reader, targetClass)); - } finally { - IOUtils.closeQuietly(reader); - } - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/PrimitiveAnswer.java b/org.argeo.server.core/src/org/argeo/server/PrimitiveAnswer.java deleted file mode 100644 index c69ffedb8..000000000 --- a/org.argeo.server.core/src/org/argeo/server/PrimitiveAnswer.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server; - -/** - * Answer to a request to a remote service that sends back only one primitive - */ -public class PrimitiveAnswer { - - private Object primitive; - - /** Canonical constructor */ - public PrimitiveAnswer(Object primitive) { - this.primitive = primitive; - } - - public Object getValue() { - return primitive; - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/Serializer.java b/org.argeo.server.core/src/org/argeo/server/Serializer.java deleted file mode 100644 index 890b17cd4..000000000 --- a/org.argeo.server.core/src/org/argeo/server/Serializer.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server; - -import java.io.Writer; - -public interface Serializer { - /** Will be removed soon. Use {@link #serialize(Object, Writer)} instead. */ - @Deprecated - public void serialize(Writer writer, Object obj); - - public void serialize(Object obj, Writer writer); -} diff --git a/org.argeo.server.core/src/org/argeo/server/ServerAnswer.java b/org.argeo.server.core/src/org/argeo/server/ServerAnswer.java deleted file mode 100644 index 2f9cbee1d..000000000 --- a/org.argeo.server.core/src/org/argeo/server/ServerAnswer.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server; - -import java.io.PrintWriter; -import java.io.StringWriter; - -import org.apache.commons.io.IOUtils; -import org.argeo.ArgeoException; - -/** Answer to an execution of a remote service which performed changes. */ -public class ServerAnswer { - public final static String OK = "OK"; - public final static String ERROR = "ERROR"; - - private String status = OK; - private String message = ""; - - // TODO: add an exception field - - /** Canonical constructor */ - public ServerAnswer(String status, String message) { - setStatus(status); - if (message == null) - throw new ArgeoException("Message cannot be null"); - this.message = message; - } - - /** Empty constructor */ - public ServerAnswer() { - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - if (status == null || (!status.equals(OK) && !status.equals(ERROR))) - throw new ArgeoException("Bad status format: " + status); - this.status = status; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public Boolean isOk() { - return status.equals(OK); - } - - public Boolean isError() { - return status.equals(ERROR); - } - - public static ServerAnswer error(String message) { - return new ServerAnswer(ERROR, message); - } - - public static ServerAnswer error(Throwable e) { - StringWriter writer = new StringWriter(); - try { - e.printStackTrace(new PrintWriter(writer)); - return new ServerAnswer(ERROR, writer.toString()); - } finally { - IOUtils.closeQuietly(writer); - } - } - - public static ServerAnswer ok(String message) { - return new ServerAnswer(OK, message); - } - - @Override - public String toString() { - return "ServerAnswer{status:" + status + ", message:" + message + "}"; - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/ServerSerializer.java b/org.argeo.server.core/src/org/argeo/server/ServerSerializer.java deleted file mode 100644 index cdb163214..000000000 --- a/org.argeo.server.core/src/org/argeo/server/ServerSerializer.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -public interface ServerSerializer { - public void serialize(Object obj, HttpServletRequest request, - HttpServletResponse response); -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/AbstractAtomicBackup.java b/org.argeo.server.core/src/org/argeo/server/backup/AbstractAtomicBackup.java deleted file mode 100644 index 89c53e680..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/AbstractAtomicBackup.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSystemManager; -import org.apache.commons.vfs2.FileSystemOptions; -import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder; -import org.argeo.ArgeoException; - -/** - * Simplify atomic backups implementation, especially by managing VFS. - */ -public abstract class AbstractAtomicBackup implements AtomicBackup { - private String name; - private String compression = "bz2"; - - protected abstract void writeBackup(FileObject targetFo); - - public AbstractAtomicBackup() { - } - - public AbstractAtomicBackup(String name) { - this.name = name; - } - - public void init() { - if (name == null) - throw new ArgeoException("Atomic backup name must be set"); - } - - public void destroy() { - - } - - @Override - public String backup(FileSystemManager fileSystemManager, - String backupsBase, BackupContext backupContext, - FileSystemOptions opts) { - if (name == null) - throw new ArgeoException("Atomic backup name must be set"); - - FileObject targetFo = null; - try { - if (backupsBase.startsWith("sftp:")) - SftpFileSystemConfigBuilder.getInstance() - .setStrictHostKeyChecking(opts, "no"); - if (compression == null || compression.equals("none")) - targetFo = fileSystemManager.resolveFile(backupsBase + '/' - + backupContext.getRelativeFolder() + '/' + name, opts); - else if (compression.equals("bz2")) - targetFo = fileSystemManager.resolveFile("bz2:" + backupsBase - + '/' + backupContext.getRelativeFolder() + '/' + name - + ".bz2" + "!" + name, opts); - else if (compression.equals("gz")) - targetFo = fileSystemManager.resolveFile("gz:" + backupsBase - + '/' + backupContext.getRelativeFolder() + '/' + name - + ".gz" + "!" + name, opts); - else - throw new ArgeoException("Unsupported compression " - + compression); - - writeBackup(targetFo); - - return targetFo.toString(); - } catch (Exception e) { - throw new ArgeoException("Cannot backup " + name + " to " - + targetFo, e); - } finally { - BackupUtils.closeFOQuietly(targetFo); - } - } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setCompression(String compression) { - this.compression = compression; - } -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/AtomicBackup.java b/org.argeo.server.core/src/org/argeo/server/backup/AtomicBackup.java deleted file mode 100644 index 1f3eb942d..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/AtomicBackup.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import org.apache.commons.vfs2.FileSystemManager; -import org.apache.commons.vfs2.FileSystemOptions; - -/** Performs the backup of a single component, typically a database dump */ -public interface AtomicBackup { - /** Name identifiying this backup */ - public String getName(); - - /** - * Retrieves the data of the component in a format that allows to restore - * the component - * - * @param backupContext - * the context of this backup - * @return the VFS URI of the generated file or directory - */ - public String backup(FileSystemManager fileSystemManager, - String backupsBase, BackupContext backupContext, - FileSystemOptions opts); -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/BackupContext.java b/org.argeo.server.core/src/org/argeo/server/backup/BackupContext.java deleted file mode 100644 index 5f6442f04..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/BackupContext.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import java.text.DateFormat; -import java.util.Date; - -/** - * Transient information of a given backup, centralizing common information such - * as timestamp and location. - */ -public interface BackupContext { - /** Backup date */ - public Date getTimestamp(); - - /** Formatted backup date */ - public String getTimestampAsString(); - - /** System name */ - public String getSystemName(); - - /** Local base */ - public String getRelativeFolder(); - - /** Date format */ - public DateFormat getDateFormat(); -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/BackupFileSystemManager.java b/org.argeo.server.core/src/org/argeo/server/backup/BackupFileSystemManager.java deleted file mode 100644 index c963c303d..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/BackupFileSystemManager.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.impl.DefaultFileSystemManager; -import org.apache.commons.vfs2.provider.bzip2.Bzip2FileProvider; -import org.apache.commons.vfs2.provider.ftp.FtpFileProvider; -import org.apache.commons.vfs2.provider.gzip.GzipFileProvider; -import org.apache.commons.vfs2.provider.local.DefaultLocalFileProvider; -import org.apache.commons.vfs2.provider.ram.RamFileProvider; -import org.apache.commons.vfs2.provider.sftp.SftpFileProvider; -import org.apache.commons.vfs2.provider.url.UrlFileProvider; -import org.argeo.ArgeoException; - -/** - * Programatically configured VFS file system manager which can be declared as a - * bean and associated with a life cycle (methods - * {@link DefaultFileSystemManager#init()} and - * {@link DefaultFileSystemManager#closet()}). Supports bz2, file, ram, gzip, - * ftp, sftp - */ -public class BackupFileSystemManager extends DefaultFileSystemManager { - - public BackupFileSystemManager() { - super(); - try { - addProvider("file", new DefaultLocalFileProvider()); - addProvider("bz2", new Bzip2FileProvider()); - addProvider("ftp", new FtpFileProvider()); - addProvider("sftp", new SftpFileProvider()); - addProvider("gzip", new GzipFileProvider()); - addProvider("ram", new RamFileProvider()); - setDefaultProvider(new UrlFileProvider()); - } catch (FileSystemException e) { - throw new ArgeoException("Cannot configure backup file provider", e); - } - } -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/BackupPurge.java b/org.argeo.server.core/src/org/argeo/server/backup/BackupPurge.java deleted file mode 100644 index 4937b8eb9..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/BackupPurge.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import java.text.DateFormat; - -import org.apache.commons.vfs2.FileSystemManager; -import org.apache.commons.vfs2.FileSystemOptions; - -/** Purges previous backups */ -public interface BackupPurge { - /** - * Purge the backups identified by these arguments. Although these are the - * same fields as a {@link BackupContext} we don't pass it as argument since - * we want to use this interface to purge remote backups as well (that is, - * with a different base), or outside the scope of a running backup. - */ - public void purge(FileSystemManager fileSystemManager, String base, - String name, DateFormat dateFormat, FileSystemOptions opts); -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/BackupUtils.java b/org.argeo.server.core/src/org/argeo/server/backup/BackupUtils.java deleted file mode 100644 index 4eb3830d8..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/BackupUtils.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import org.apache.commons.vfs2.FileObject; - -/** Backup utilities */ -public class BackupUtils { - /** Close a file object quietly even if it is null or throws an exception. */ - public static void closeFOQuietly(FileObject fo) { - if (fo != null) { - try { - fo.close(); - } catch (Exception e) { - // silent - } - } - } - - /** Prevents instantiation */ - private BackupUtils() { - } -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/MySqlBackup.java b/org.argeo.server.core/src/org/argeo/server/backup/MySqlBackup.java deleted file mode 100644 index 4eb662cbc..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/MySqlBackup.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import org.apache.commons.vfs2.FileObject; - -/** Backups a MySQL database using mysqldump. */ -public class MySqlBackup extends OsCallBackup { - private String mysqldumpLocation = "/usr/bin/mysqldump"; - - private String dbUser; - private String dbPassword; - private String dbName; - - public MySqlBackup() { - } - - public MySqlBackup(String dbUser, String dbPassword, String dbName) { - this.dbUser = dbUser; - this.dbPassword = dbPassword; - this.dbName = dbName; - init(); - } - - @Override - public void init() { - if (getName() == null) - setName(dbName + ".mysql"); - super.init(); - } - - @Override - public void writeBackup(FileObject targetFo) { - if (getCommand() == null) - setCommand(mysqldumpLocation - + " --lock-tables --add-locks --add-drop-table" - + " -u ${dbUser} --password=${dbPassword} --databases ${dbName}"); - getVariables().put("dbUser", dbUser); - getVariables().put("dbPassword", dbPassword); - getVariables().put("dbName", dbName); - - super.writeBackup(targetFo); - } - - public void setDbUser(String dbUser) { - this.dbUser = dbUser; - } - - public void setDbPassword(String dbPassword) { - this.dbPassword = dbPassword; - } - - public void setDbName(String dbName) { - this.dbName = dbName; - } - - public void setMysqldumpLocation(String mysqldumpLocation) { - this.mysqldumpLocation = mysqldumpLocation; - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/OpenLdapBackup.java b/org.argeo.server.core/src/org/argeo/server/backup/OpenLdapBackup.java deleted file mode 100644 index bfebe263e..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/OpenLdapBackup.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import org.apache.commons.vfs2.FileObject; -import org.argeo.ArgeoException; - -/** Backups an OpenLDAP server using slapcat */ -public class OpenLdapBackup extends OsCallBackup { - private String slapcatLocation = "/usr/sbin/slapcat"; - private String slapdConfLocation = "/etc/openldap/slapd.conf"; - private String baseDn; - - public OpenLdapBackup() { - super(); - } - - public OpenLdapBackup(String baseDn) { - super(); - this.baseDn = baseDn; - } - - @Override - public void writeBackup(FileObject targetFo) { - if (baseDn == null) - throw new ArgeoException("Base DN must be set"); - - if (getCommand() == null) - setCommand(slapcatLocation - + " -f ${slapdConfLocation} -b '${baseDn}'"); - getVariables().put("slapdConfLocation", slapdConfLocation); - getVariables().put("baseDn", baseDn); - - super.writeBackup(targetFo); - } - - public void setSlapcatLocation(String slapcatLocation) { - this.slapcatLocation = slapcatLocation; - } - - public void setSlapdConfLocation(String slapdConfLocation) { - this.slapdConfLocation = slapdConfLocation; - } - - public void setBaseDn(String baseDn) { - this.baseDn = baseDn; - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/OsCallBackup.java b/org.argeo.server.core/src/org/argeo/server/backup/OsCallBackup.java deleted file mode 100644 index 788ba52db..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/OsCallBackup.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import java.io.ByteArrayOutputStream; -import java.util.HashMap; -import java.util.Map; - -import org.apache.commons.exec.CommandLine; -import org.apache.commons.exec.DefaultExecutor; -import org.apache.commons.exec.ExecuteException; -import org.apache.commons.exec.ExecuteStreamHandler; -import org.apache.commons.exec.Executor; -import org.apache.commons.exec.PumpStreamHandler; -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs2.FileContent; -import org.apache.commons.vfs2.FileObject; -import org.argeo.ArgeoException; - -/** - * Runs an OS command and save its standard output as a file. Typically used for - * MySQL or OpenLDAP dumps. - */ -public class OsCallBackup extends AbstractAtomicBackup { - private final static Log log = LogFactory.getLog(OsCallBackup.class); - - private String command; - private Map variables = new HashMap(); - private Executor executor = new DefaultExecutor(); - - private Map environment = new HashMap(); - - /** Name of the sudo user, root if "", not sudo if null */ - private String sudo = null; - - public OsCallBackup() { - } - - public OsCallBackup(String name) { - super(name); - } - - public OsCallBackup(String name, String command) { - super(name); - this.command = command; - } - - @Override - public void writeBackup(FileObject targetFo) { - String commandToUse = command; - - // sudo - if (sudo != null) { - if (sudo.equals("")) - commandToUse = "sudo " + commandToUse; - else - commandToUse = "sudo -u " + sudo + " " + commandToUse; - } - - CommandLine commandLine = CommandLine.parse(commandToUse, variables); - ByteArrayOutputStream errBos = new ByteArrayOutputStream(); - if (log.isTraceEnabled()) - log.trace(commandLine.toString()); - - try { - // stdout - FileContent targetContent = targetFo.getContent(); - // stderr - ExecuteStreamHandler streamHandler = new PumpStreamHandler( - targetContent.getOutputStream(), errBos); - executor.setStreamHandler(streamHandler); - executor.execute(commandLine, environment); - } catch (ExecuteException e) { - byte[] err = errBos.toByteArray(); - String errStr = new String(err); - throw new ArgeoException("Process " + commandLine + " failed (" - + e.getExitValue() + "): " + errStr, e); - } catch (Exception e) { - byte[] err = errBos.toByteArray(); - String errStr = new String(err); - throw new ArgeoException("Process " + commandLine + " failed: " - + errStr, e); - } finally { - IOUtils.closeQuietly(errBos); - } - } - - public void setCommand(String command) { - this.command = command; - } - - protected String getCommand() { - return command; - } - - /** - * A reference to the environment variables that will be passed to the - * process. Empty by default. - */ - protected Map getEnvironment() { - return environment; - } - - protected Map getVariables() { - return variables; - } - - public void setVariables(Map variables) { - this.variables = variables; - } - - public void setExecutor(Executor executor) { - this.executor = executor; - } - - public void setSudo(String sudo) { - this.sudo = sudo; - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/PostgreSqlBackup.java b/org.argeo.server.core/src/org/argeo/server/backup/PostgreSqlBackup.java deleted file mode 100644 index 805954b09..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/PostgreSqlBackup.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import org.apache.commons.vfs2.FileObject; - -/** Backups a PostgreSQL database using pg_dump. */ -public class PostgreSqlBackup extends OsCallBackup { - /** - * PostgreSQL password environment variable (see - * http://stackoverflow.com/questions - * /2893954/how-to-pass-in-password-to-pg-dump) - */ - protected final static String PGPASSWORD = "PGPASSWORD"; - - private String pgDumpLocation = "/usr/bin/pg_dump"; - - private String dbUser; - private String dbPassword; - private String dbName; - - public PostgreSqlBackup() { - super(); - } - - public PostgreSqlBackup(String dbUser, String dbPassword, String dbName) { - this.dbUser = dbUser; - this.dbPassword = dbPassword; - this.dbName = dbName; - init(); - } - - @Override - public void init() { - // disable compression since pg_dump is used with -Fc option - setCompression(null); - - if (getName() == null) - setName(dbName + ".pgdump"); - super.init(); - } - - @Override - public void writeBackup(FileObject targetFo) { - if (getCommand() == null) { - getEnvironment().put(PGPASSWORD, dbPassword); - setCommand(pgDumpLocation + " -Fc" + " -U ${dbUser} ${dbName}"); - } - getVariables().put("dbUser", dbUser); - getVariables().put("dbPassword", dbPassword); - getVariables().put("dbName", dbName); - - super.writeBackup(targetFo); - } - - public void setDbUser(String dbUser) { - this.dbUser = dbUser; - } - - public void setDbPassword(String dbPassword) { - this.dbPassword = dbPassword; - } - - public void setDbName(String dbName) { - this.dbName = dbName; - } - - public void setPgDumpLocation(String mysqldumpLocation) { - this.pgDumpLocation = mysqldumpLocation; - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/SimpleBackupContext.java b/org.argeo.server.core/src/org/argeo/server/backup/SimpleBackupContext.java deleted file mode 100644 index 33e45e654..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/SimpleBackupContext.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; - -import org.apache.commons.vfs2.FileSystemManager; - -/** Simple implementation of a backup context */ -public class SimpleBackupContext implements BackupContext { - private DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmm"); - private final Date timestamp; - private final String name; - - private final FileSystemManager fileSystemManager; - - public SimpleBackupContext(FileSystemManager fileSystemManager, - String backupsBase, String name) { - this.name = name; - this.timestamp = new Date(); - this.fileSystemManager = fileSystemManager; - } - - public Date getTimestamp() { - return timestamp; - } - - public String getTimestampAsString() { - return dateFormat.format(timestamp); - } - - public String getSystemName() { - return name; - } - - public String getRelativeFolder() { - return name + '/' + getTimestampAsString(); - } - - public DateFormat getDateFormat() { - return dateFormat; - } - - public FileSystemManager getFileSystemManager() { - return fileSystemManager; - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/SimpleBackupPurge.java b/org.argeo.server.core/src/org/argeo/server/backup/SimpleBackupPurge.java deleted file mode 100644 index ad269f77b..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/SimpleBackupPurge.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import java.text.DateFormat; -import java.util.Date; -import java.util.SortedMap; -import java.util.TreeMap; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSystemManager; -import org.apache.commons.vfs2.FileSystemOptions; -import org.apache.commons.vfs2.Selectors; -import org.argeo.ArgeoException; -import org.joda.time.DateTime; -import org.joda.time.Period; - -/** Simple backup purge which keeps backups only for a given number of days */ -public class SimpleBackupPurge implements BackupPurge { - private final static Log log = LogFactory.getLog(SimpleBackupPurge.class); - - private Integer daysKept = 30; - - @Override - public void purge(FileSystemManager fileSystemManager, String base, - String name, DateFormat dateFormat, FileSystemOptions opts) { - try { - DateTime nowDt = new DateTime(); - FileObject baseFo = fileSystemManager.resolveFile( - base + '/' + name, opts); - - SortedMap toDelete = new TreeMap(); - int backupCount = 0; - - // make sure base dir exists - baseFo.createFolder(); - - // scan backups and list those which should be deleted - for (FileObject backupFo : baseFo.getChildren()) { - String backupName = backupFo.getName().getBaseName(); - Date backupDate = dateFormat.parse(backupName); - backupCount++; - - DateTime backupDt = new DateTime(backupDate.getTime()); - Period sinceThen = new Period(backupDt, nowDt); - int days = sinceThen.getDays(); - // int days = sinceThen.getMinutes(); - if (days > daysKept) { - toDelete.put(backupDt, backupFo); - } - } - - if (toDelete.size() != 0 && toDelete.size() == backupCount) { - // all backups would be deleted - // but we want to keep at least one - DateTime lastBackupDt = toDelete.firstKey(); - FileObject keptFo = toDelete.remove(lastBackupDt); - log.warn("Backup " + keptFo - + " kept although it is older than " + daysKept - + " days."); - } - - // delete old backups - for (FileObject backupFo : toDelete.values()) { - backupFo.delete(Selectors.SELECT_ALL); - if (log.isDebugEnabled()) - log.debug("Deleted backup " + backupFo); - } - } catch (Exception e) { - throw new ArgeoException("Could not purge previous backups", e); - } - - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/SvnBackup.java b/org.argeo.server.core/src/org/argeo/server/backup/SvnBackup.java deleted file mode 100644 index d157ecf45..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/SvnBackup.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import java.io.File; - -import org.apache.commons.vfs2.FileObject; - -/** Backups a Subversion repository using svnadmin. */ -public class SvnBackup extends OsCallBackup { - private String svnadminLocation = "/usr/bin/svnadmin"; - - private String repoLocation; - private String repoName; - - public SvnBackup() { - } - - public SvnBackup(String repoLocation) { - this.repoLocation = repoLocation; - init(); - } - - @Override - public void init() { - // use directory as repo name - if (repoName == null) - repoName = new File(repoLocation).getName(); - - if (getName() == null) - setName(repoName + ".svndump"); - super.init(); - } - - @Override - public void writeBackup(FileObject targetFo) { - if (getCommand() == null) { - setCommand(svnadminLocation + " dump " + " ${repoLocation}"); - } - getVariables().put("repoLocation", repoLocation); - - super.writeBackup(targetFo); - } - - public void setRepoLocation(String repoLocation) { - this.repoLocation = repoLocation; - } - - public void setRepoName(String repoName) { - this.repoName = repoName; - } - - public void setSvnadminLocation(String mysqldumpLocation) { - this.svnadminLocation = mysqldumpLocation; - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/backup/SystemBackup.java b/org.argeo.server.core/src/org/argeo/server/backup/SystemBackup.java deleted file mode 100644 index b7ce02996..000000000 --- a/org.argeo.server.core/src/org/argeo/server/backup/SystemBackup.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.backup; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.commons.vfs2.FileObject; -import org.apache.commons.vfs2.FileSystemException; -import org.apache.commons.vfs2.FileSystemManager; -import org.apache.commons.vfs2.FileSystemOptions; -import org.apache.commons.vfs2.Selectors; -import org.apache.commons.vfs2.UserAuthenticator; -import org.apache.commons.vfs2.auth.StaticUserAuthenticator; -import org.apache.commons.vfs2.impl.DefaultFileSystemConfigBuilder; -import org.apache.commons.vfs2.impl.StandardFileSystemManager; -import org.argeo.ArgeoException; - -/** - * Combines multiple backups and transfer them to a remote location. Purges - * remote and local data based on certain criteria. - */ -public class SystemBackup implements Runnable { - private final static Log log = LogFactory.getLog(SystemBackup.class); - - private FileSystemManager fileSystemManager; - private UserAuthenticator userAuthenticator = null; - - private String backupsBase; - private String systemName; - - private List atomicBackups = new ArrayList(); - private BackupPurge backupPurge = new SimpleBackupPurge(); - - private Map remoteBases = new HashMap(); - - @Override - public void run() { - if (atomicBackups.size() == 0) - throw new ArgeoException("No atomic backup listed"); - List failures = new ArrayList(); - - SimpleBackupContext backupContext = new SimpleBackupContext( - fileSystemManager, backupsBase, systemName); - - // purge older backups - FileSystemOptions opts = new FileSystemOptions(); - try { - DefaultFileSystemConfigBuilder.getInstance().setUserAuthenticator( - opts, userAuthenticator); - } catch (FileSystemException e) { - throw new ArgeoException("Cannot create authentication", e); - } - - try { - - backupPurge.purge(fileSystemManager, backupsBase, systemName, - backupContext.getDateFormat(), opts); - } catch (Exception e) { - failures.add("Purge " + backupsBase + " failed: " + e.getMessage()); - log.error("Purge of " + backupsBase + " failed", e); - } - - // perform backup - for (AtomicBackup atomickBackup : atomicBackups) { - try { - String target = atomickBackup.backup(fileSystemManager, - backupsBase, backupContext, opts); - if (log.isDebugEnabled()) - log.debug("Performed backup " + target); - } catch (Exception e) { - String msg = "Atomic backup " + atomickBackup.getName() - + " failed: " + ArgeoException.chainCausesMessages(e); - failures.add(msg); - log.error(msg); - if (log.isTraceEnabled()) - log.trace( - "Stacktrace of atomic backup " - + atomickBackup.getName() + " failure.", e); - } - } - - // dispatch to remote - for (String remoteBase : remoteBases.keySet()) { - FileObject localBaseFo = null; - FileObject remoteBaseFo = null; - UserAuthenticator auth = remoteBases.get(remoteBase); - - // authentication - FileSystemOptions remoteOpts = new FileSystemOptions(); - try { - DefaultFileSystemConfigBuilder.getInstance() - .setUserAuthenticator(remoteOpts, auth); - backupPurge.purge(fileSystemManager, remoteBase, systemName, - backupContext.getDateFormat(), remoteOpts); - } catch (Exception e) { - failures.add("Purge " + remoteBase + " failed: " - + e.getMessage()); - log.error("Cannot purge " + remoteBase, e); - } - - try { - localBaseFo = fileSystemManager.resolveFile(backupsBase + '/' - + backupContext.getRelativeFolder(), opts); - remoteBaseFo = fileSystemManager.resolveFile(remoteBase + '/' - + backupContext.getRelativeFolder(), remoteOpts); - remoteBaseFo.copyFrom(localBaseFo, Selectors.SELECT_ALL); - if (log.isDebugEnabled()) - log.debug("Copied backup to " + remoteBaseFo + " from " - + localBaseFo); - // } - } catch (Exception e) { - failures.add("Dispatch to " + remoteBase + " failed: " - + e.getMessage()); - log.error( - "Cannot dispatch backups from " - + backupContext.getRelativeFolder() + " to " - + remoteBase, e); - } - BackupUtils.closeFOQuietly(localBaseFo); - BackupUtils.closeFOQuietly(remoteBaseFo); - } - - int failureCount = 0; - if (failures.size() > 0) { - StringBuffer buf = new StringBuffer(); - for (String failure : failures) { - buf.append('\n').append(failureCount).append(" - ") - .append(failure); - failureCount++; - } - throw new ArgeoException(failureCount - + " error(s) when running the backup," - + " check the logs and the backups as soon as possible." - + buf); - } - } - - public void setFileSystemManager(FileSystemManager fileSystemManager) { - this.fileSystemManager = fileSystemManager; - } - - public void setBackupsBase(String backupsBase) { - this.backupsBase = backupsBase; - } - - public void setSystemName(String name) { - this.systemName = name; - } - - public void setAtomicBackups(List atomicBackups) { - this.atomicBackups = atomicBackups; - } - - public void setBackupPurge(BackupPurge backupPurge) { - this.backupPurge = backupPurge; - } - - public void setUserAuthenticator(UserAuthenticator userAuthenticator) { - this.userAuthenticator = userAuthenticator; - } - - public void setRemoteBases(Map remoteBases) { - this.remoteBases = remoteBases; - } - - public static void main(String args[]) { - while (true) { - try { - StandardFileSystemManager fsm = new StandardFileSystemManager(); - fsm.init(); - - SystemBackup systemBackup = new SystemBackup(); - systemBackup.setSystemName("mySystem"); - systemBackup - .setBackupsBase("/home/mbaudier/dev/src/commons/server/runtime/org.argeo.server.core/target"); - systemBackup.setFileSystemManager(fsm); - - List atomicBackups = new ArrayList(); - - MySqlBackup mySqlBackup = new MySqlBackup("root", "", "test"); - atomicBackups.add(mySqlBackup); - PostgreSqlBackup postgreSqlBackup = new PostgreSqlBackup( - "argeo", "argeo", "gis_template"); - atomicBackups.add(postgreSqlBackup); - SvnBackup svnBackup = new SvnBackup( - "/home/mbaudier/tmp/testsvnrepo"); - atomicBackups.add(svnBackup); - - systemBackup.setAtomicBackups(atomicBackups); - - Map remoteBases = new HashMap(); - StaticUserAuthenticator userAuthenticator = new StaticUserAuthenticator( - null, "demo", "demo"); - remoteBases.put("sftp://localhost/home/mbaudier/test", - userAuthenticator); - systemBackup.setRemoteBases(remoteBases); - - systemBackup.run(); - - fsm.close(); - } catch (FileSystemException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - System.exit(1); - } - - // wait - try { - Thread.sleep(120 * 1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } -} diff --git a/org.argeo.server.core/src/org/argeo/server/dao/AbstractMemoryDaoSupport.java b/org.argeo.server.core/src/org/argeo/server/dao/AbstractMemoryDaoSupport.java deleted file mode 100644 index f9af51bcf..000000000 --- a/org.argeo.server.core/src/org/argeo/server/dao/AbstractMemoryDaoSupport.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.dao; - -import java.beans.PropertyEditor; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import org.apache.commons.io.IOUtils; -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; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.core.io.Resource; - -public abstract class AbstractMemoryDaoSupport implements LightDaoSupport, - ApplicationContextAware, InitializingBean { - private final static Log log = LogFactory - .getLog(AbstractMemoryDaoSupport.class); - - private ClassLoader classLoader = getClass().getClassLoader(); - private ApplicationContext applicationContext; - private List> additionalClasses = new ArrayList>(); - - private Map, Map> model = new HashMap, Map>(); - - private Map externalRefs = new HashMap(); - - private List scannedPackages = new ArrayList(); - - private List resources = new ArrayList(); - - private Map, PropertyEditor> customEditors = new HashMap, PropertyEditor>();; - - protected abstract void load(InputStream in, List references); - - protected abstract Object findInternalRef(Reference reference); - - public void afterPropertiesSet() throws Exception { - init(); - } - - public void init() { - for (PropertyEditor propertyEditor : customEditors.values()) - if (propertyEditor instanceof LightDaoAware) { - ((LightDaoAware) propertyEditor).setLightDaoSupport(this); - } - - // Load data - List references = new ArrayList(); - - for (Resource res : resources) { - InputStream in = null; - try { - in = res.getInputStream(); - load(in, references); - } catch (Exception e) { - throw new ArgeoException("Cannot load stream", e); - } finally { - IOUtils.closeQuietly(in); - } - } - - // Inject references - for (Reference ref : references) { - injectReference(ref); - } - if (log.isDebugEnabled()) - log.debug(references.size() + " references linked"); - } - - public List> getSupportedClasses() { - List> res = new ArrayList>(); - res.addAll(additionalClasses); - res.addAll(model.keySet()); - return res; - } - - protected void injectReference(Reference reference) { - BeanWrapper bw = new BeanWrapperImpl(reference.object); - Object targetObject; - if (reference.getExternalRef() != null) { - String ref = reference.getExternalRef(); - if (externalRefs.containsKey(ref)) - targetObject = externalRefs.get(ref); - else if (applicationContext != null) - targetObject = applicationContext.getBean(ref); - else { - targetObject = null; - log.warn("Ref " + ref + " not found"); - } - } else { - targetObject = findInternalRef(reference); - } - bw.setPropertyValue(reference.property, targetObject); - - } - - protected BeanWrapper newBeanWrapper(Class targetClass) { - BeanWrapperImpl bw = new BeanWrapperImpl(targetClass); - for (Class clss : customEditors.keySet()) - bw.registerCustomEditor(clss, customEditors.get(clss)); - return bw; - } - - @SuppressWarnings("unchecked") - public T getByKey(Class clss, Object key) { - if (key == null) - throw new ArgeoException("Key is null for " + clss); - return (T) model.get(findClass(clss)).get(key); - } - - /** - * Slow. - * - * @return the first found - */ - public T getByField(Class clss, String field, Object value) { - List all = list(clss, null); - T res = null; - for (T obj : all) { - if (new BeanWrapperImpl(obj).getPropertyValue(field).equals(value)) { - res = obj; - break; - } - } - return res; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public List list(Class clss, Object filter) { - List res = new ArrayList(); - - Class classToUse = findClass(clss); - if (classToUse != null) - res.addAll((Collection) model.get(classToUse).values()); - - if (applicationContext != null) - res.addAll(applicationContext.getBeansOfType(clss).values()); - - return res; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - protected Class findClass(Class parent) { - if (model.containsKey(parent)) - return parent; - - for (Class clss : model.keySet()) { - if (parent.isAssignableFrom(clss)) - return clss;// return the first found - } - if (log.isDebugEnabled()) - log.warn("No class found for " + parent.getName()); - return null; - } - - public void setApplicationContext(ApplicationContext applicationContext) - throws BeansException { - this.applicationContext = applicationContext; - } - - /** - * When it should be stored under a different class (e.g. super class or - * interface) - */ - public void saveOrUpdate(Object key, Object value, Class clss) { - if (!model.containsKey(clss)) - model.put(clss, new TreeMap()); - model.get(clss).put(key, value); - } - - protected ClassLoader getClassLoader() { - return classLoader; - } - - public void setExternalRefs(Map externalRefs) { - this.externalRefs = externalRefs; - } - - public Map getExternalRefs() { - return externalRefs; - } - - public void setScannedPackages(List scannedPackages) { - this.scannedPackages = scannedPackages; - } - - public List getScannedPackages() { - return scannedPackages; - } - - public void setResources(List workbooks) { - this.resources = workbooks; - } - - public List getResources() { - return resources; - } - - public void setClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - public List> getAdditionalClasses() { - return additionalClasses; - } - - public void setAdditionalClasses(List> additionalClasses) { - this.additionalClasses = additionalClasses; - } - - public void setCustomEditors(Map, PropertyEditor> propertyEditors) { - this.customEditors = propertyEditors; - } - - protected static class Reference { - private Object object; - private String property; - private String externalRef; - - public Reference(Object object, String property, String externalRef) { - this.object = object; - this.property = property; - this.externalRef = externalRef; - } - - public Object getObject() { - return object; - } - - public String getProperty() { - return property; - } - - public String getExternalRef() { - return externalRef; - } - - } -} diff --git a/org.argeo.server.core/src/org/argeo/server/dao/AbstractTabularDaoSupport.java b/org.argeo.server.core/src/org/argeo/server/dao/AbstractTabularDaoSupport.java deleted file mode 100644 index 1ca5a100c..000000000 --- a/org.argeo.server.core/src/org/argeo/server/dao/AbstractTabularDaoSupport.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.dao; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; - -public abstract class AbstractTabularDaoSupport extends - AbstractMemoryDaoSupport { - private final static Log log = LogFactory - .getLog(AbstractTabularDaoSupport.class); - - private Map> tabularView = new HashMap>(); - - @Override - protected Object findInternalRef(Reference reference) { - TabularInternalReference tabReference = (TabularInternalReference) reference; - return getFromTabularView(tabReference.getTargetTableName(), - tabReference.getTargetRow()); - } - - protected Object getFromTabularView(String tableName, Integer row) { - return tabularView.get(tableName).get(row - 2); - } - - protected void registerInTabularView(String tableName, Object object) { - if (!tabularView.containsKey(tableName)) - tabularView.put(tableName, new ArrayList()); - tabularView.get(tableName).add(object); - } - - protected Class findClassToInstantiate(String tableName) { - // TODO: ability to map sheet names and class names - String className = tableName; - Class clss = null; - try { - clss = getClassLoader().loadClass(className); - return clss; - } catch (ClassNotFoundException e) { - // silent - } - - scannedPkgs: for (String pkg : getScannedPackages()) { - try { - clss = getClassLoader().loadClass(pkg.trim() + "." + className); - break scannedPkgs; - } catch (ClassNotFoundException e) { - // silent - if (log.isTraceEnabled()) - log.trace(e.getMessage()); - } - } - - if (clss == null) - throw new ArgeoException("Cannot find a class for table " - + tableName); - - return clss; - } - - protected static class TabularInternalReference extends Reference { - private String targetTableName; - private Integer targetRow; - - public TabularInternalReference(Object object, String property, - String targetSheet, Integer targetRow) { - super(object, property, null); - this.targetTableName = targetSheet; - this.targetRow = targetRow; - } - - public String getTargetTableName() { - return targetTableName; - } - - public Integer getTargetRow() { - return targetRow; - } - - } -} diff --git a/org.argeo.server.core/src/org/argeo/server/dao/LightDaoAware.java b/org.argeo.server.core/src/org/argeo/server/dao/LightDaoAware.java deleted file mode 100644 index 5ae7bea1e..000000000 --- a/org.argeo.server.core/src/org/argeo/server/dao/LightDaoAware.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.dao; - -public interface LightDaoAware { - public void setLightDaoSupport(LightDaoSupport lightDaoSupport); -} diff --git a/org.argeo.server.core/src/org/argeo/server/dao/LightDaoPropertyEditor.java b/org.argeo.server.core/src/org/argeo/server/dao/LightDaoPropertyEditor.java deleted file mode 100644 index de6ba7084..000000000 --- a/org.argeo.server.core/src/org/argeo/server/dao/LightDaoPropertyEditor.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.dao; - -import java.beans.PropertyEditorSupport; - -import org.argeo.ArgeoException; - -public class LightDaoPropertyEditor extends PropertyEditorSupport implements - LightDaoAware { - private LightDaoSupport lightDaoSupport; - - private Class targetClass; - /** Can be null */ - private String businessIdField; - - @Override - public String getAsText() { - return getValue().toString(); - } - - @Override - public void setAsText(String text) throws IllegalArgumentException { - if (targetClass == null) - throw new ArgeoException("Target class cannot be null"); - - if (businessIdField != null) - setValue(lightDaoSupport.getByField(targetClass, businessIdField, - text)); - else - setValue(lightDaoSupport.getByKey(targetClass, text)); - } - - public void setLightDaoSupport(LightDaoSupport lightDaoSupport) { - this.lightDaoSupport = lightDaoSupport; - } - - public void setTargetClass(Class targetClass) { - this.targetClass = targetClass; - } - - public void setBusinessIdField(String businessIdField) { - this.businessIdField = businessIdField; - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/dao/LightDaoSupport.java b/org.argeo.server.core/src/org/argeo/server/dao/LightDaoSupport.java deleted file mode 100644 index 6ea1b754d..000000000 --- a/org.argeo.server.core/src/org/argeo/server/dao/LightDaoSupport.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.dao; - -import java.util.List; - -/** Minimal generic DAO for easy to implements objects <-> storage mapping. */ -public interface LightDaoSupport { - /** Retrieve an object of a given type by its unique key. */ - public T getByKey(Class clss, Object key); - - /** Retrieve an object of a given type by the value of one of its fields. */ - public T getByField(Class clss, String field, Object value); - - /** List all objects, optionally filtering them (implementation dependent) */ - public List list(Class clss, Object filter); - - /** Lis all supported object types. */ - public List> getSupportedClasses(); - - /** Save or update an object */ - public void saveOrUpdate(Object key, Object value, Class clss); -} diff --git a/org.argeo.server.core/src/org/argeo/server/mvc/DefaultHandlerExceptionResolver.java b/org.argeo.server.core/src/org/argeo/server/mvc/DefaultHandlerExceptionResolver.java deleted file mode 100644 index 6269bd007..000000000 --- a/org.argeo.server.core/src/org/argeo/server/mvc/DefaultHandlerExceptionResolver.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.mvc; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.server.ServerAnswer; -import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.ModelAndView; - -public class DefaultHandlerExceptionResolver implements - HandlerExceptionResolver { - private final static Log log = LogFactory - .getLog(DefaultHandlerExceptionResolver.class); - - public ModelAndView resolveException(HttpServletRequest request, - HttpServletResponse response, Object handler, Exception ex) { - ModelAndView mv = new ModelAndView(); - ServerAnswer serverAnswer = ServerAnswer.error(ex); - mv.addObject(serverAnswer); - - if (log.isDebugEnabled()) - log.error(serverAnswer); - - mv.setViewName("500"); - // response.setStatus(500); - return mv; - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/mvc/EmptyViewController.java b/org.argeo.server.core/src/org/argeo/server/mvc/EmptyViewController.java deleted file mode 100644 index c83d4aeba..000000000 --- a/org.argeo.server.core/src/org/argeo/server/mvc/EmptyViewController.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.mvc; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.servlet.mvc.ParameterizableViewController; - -/** Dummy controller which simply redirects to a view (typically a JSP)*/ -public class EmptyViewController extends ParameterizableViewController { - - protected ModelAndView handleRequestInternal(HttpServletRequest request, - HttpServletResponse response) throws Exception { - ModelAndView modelAndView = new ModelAndView(); - modelAndView.setViewName(getViewName()); - return modelAndView; - - } -} diff --git a/org.argeo.server.core/src/org/argeo/server/mvc/MvcConstants.java b/org.argeo.server.core/src/org/argeo/server/mvc/MvcConstants.java deleted file mode 100644 index d5c32dc89..000000000 --- a/org.argeo.server.core/src/org/argeo/server/mvc/MvcConstants.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.mvc; - -public interface MvcConstants { - public final static String ANSWER_MODEL_KEY = "org.argeo.server.mvc.ANSWER"; - public final static String ANSWER_MODEL_KEY_AS_HTML = "org.argeo.server.mvc.ANSWER_AS_HTML"; -} diff --git a/org.argeo.server.core/src/org/argeo/server/mvc/SerializingView.java b/org.argeo.server.core/src/org/argeo/server/mvc/SerializingView.java deleted file mode 100644 index b42a9a0d2..000000000 --- a/org.argeo.server.core/src/org/argeo/server/mvc/SerializingView.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.mvc; - -import java.util.Locale; -import java.util.Map; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.argeo.ArgeoException; -import org.argeo.server.ServerAnswer; -import org.argeo.server.ServerSerializer; -import org.springframework.validation.BindingResult; -import org.springframework.web.servlet.View; -import org.springframework.web.servlet.view.AbstractView; - -/** - * Can be used as a standalone {@link View} or using - * {@link SerializingViewResolver} - */ -public class SerializingView extends AbstractView implements MvcConstants { - private final String viewName; - private final Locale locale; - - private ServerSerializer serializer; - - public SerializingView() { - this.viewName = null; - this.locale = Locale.getDefault(); - } - - public SerializingView(String viewName, Locale locale, - ServerSerializer serializer) { - this.viewName = viewName; - this.locale = locale; - this.serializer = serializer; - } - - @SuppressWarnings({ "rawtypes" }) - @Override - protected void renderMergedOutputModel(Map model, - HttpServletRequest request, HttpServletResponse response) - throws Exception { - Boolean serverAnswersAsHtml = model - .containsKey(ANSWER_MODEL_KEY_AS_HTML); - - final Object answer = findAnswerInModel(model); - - if ((answer instanceof ServerAnswer) && serverAnswersAsHtml) { - response.setContentType("text/html"); - ServerAnswer serverAnswer = (ServerAnswer) answer; - response.getWriter().append("
");
-			response.getWriter().append(serverAnswer.getMessage());
-			response.getWriter().append("
"); - } else { - serializer.serialize(answer, request, response); - } - } - - @SuppressWarnings("rawtypes") - protected Object findAnswerInModel(Map model) { - if (model.size() == 1) { - return model.values().iterator().next(); - } else if (model.size() == 2) { - boolean otherIsBindingResult = false; - Object answerValue = null; - for (Object value : model.values()) { - if (value instanceof BindingResult) - otherIsBindingResult = true; - else - answerValue = value; - } - - if (otherIsBindingResult) - return answerValue; - } - - if (model.containsKey(ANSWER_MODEL_KEY)) { - return model.get(ANSWER_MODEL_KEY); - } else if (model.containsKey(ANSWER_MODEL_KEY_AS_HTML)) { - return model.get(ANSWER_MODEL_KEY_AS_HTML); - } else if (viewName != null && model.containsKey(viewName)) { - return model.get(viewName); - } else { - if (model.size() == 0) - throw new ArgeoException("Model is empty."); - else - throw new ArgeoException( - "Model has a size different from 1. Specify a modelKey."); - } - } - - public String getViewName() { - return viewName; - } - - public Locale getLocale() { - return locale; - } - - public void setSerializer(ServerSerializer serializer) { - this.serializer = serializer; - } - -} diff --git a/org.argeo.server.core/src/org/argeo/server/mvc/SerializingViewResolver.java b/org.argeo.server.core/src/org/argeo/server/mvc/SerializingViewResolver.java deleted file mode 100644 index 93315438f..000000000 --- a/org.argeo.server.core/src/org/argeo/server/mvc/SerializingViewResolver.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.server.mvc; - -import java.util.Locale; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.server.ServerSerializer; -import org.springframework.web.servlet.View; -import org.springframework.web.servlet.view.AbstractCachingViewResolver; - -/** - * Returns a {@link SerializingView} based on the underlying. - */ -public class SerializingViewResolver extends AbstractCachingViewResolver { - private final static Log log = LogFactory - .getLog(SerializingViewResolver.class); - - private ServerSerializer serializer; - - @Override - protected View loadView(String viewName, Locale locale) throws Exception { - if (log.isTraceEnabled()) - log.trace("viewName=" + viewName); - return new SerializingView(viewName, locale, serializer); - } - - public void setSerializer(ServerSerializer serializer) { - this.serializer = serializer; - } - -} diff --git a/org.argeo.server.jackrabbit/.classpath b/org.argeo.server.jackrabbit/.classpath deleted file mode 100644 index d2953a684..000000000 --- a/org.argeo.server.jackrabbit/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/org.argeo.server.jackrabbit/.project b/org.argeo.server.jackrabbit/.project deleted file mode 100644 index a381d35e0..000000000 --- a/org.argeo.server.jackrabbit/.project +++ /dev/null @@ -1,28 +0,0 @@ - - - org.argeo.server.jackrabbit - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.pde.PluginNature - - diff --git a/org.argeo.server.jackrabbit/.settings/org.eclipse.jdt.core.prefs b/org.argeo.server.jackrabbit/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 51880a3eb..000000000 --- a/org.argeo.server.jackrabbit/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,89 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled -org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore -org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull -org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault -org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable -org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled -org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning -org.eclipse.jdt.core.compiler.problem.autoboxing=ignore -org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning -org.eclipse.jdt.core.compiler.problem.deadCode=warning -org.eclipse.jdt.core.compiler.problem.deprecation=warning -org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled -org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled -org.eclipse.jdt.core.compiler.problem.discouragedReference=warning -org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore -org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore -org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore -org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled -org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore -org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning -org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning -org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled -org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning -org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning -org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore -org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore -org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning -org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore -org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore -org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled -org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore -org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore -org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled -org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning -org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore -org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning -org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning -org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore -org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning -org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error -org.eclipse.jdt.core.compiler.problem.nullReference=warning -org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error -org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning -org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning -org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore -org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore -org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore -org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore -org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning -org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning -org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore -org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore -org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore -org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore -org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore -org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled -org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning -org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled -org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled -org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled -org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore -org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning -org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled -org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning -org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning -org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore -org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore -org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled -org.eclipse.jdt.core.compiler.problem.unusedImport=warning -org.eclipse.jdt.core.compiler.problem.unusedLabel=warning -org.eclipse.jdt.core.compiler.problem.unusedLocal=warning -org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore -org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore -org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled -org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled -org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled -org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning -org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore -org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning -org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning diff --git a/org.argeo.server.jackrabbit/bnd.bnd b/org.argeo.server.jackrabbit/bnd.bnd deleted file mode 100644 index 785086f75..000000000 --- a/org.argeo.server.jackrabbit/bnd.bnd +++ /dev/null @@ -1,7 +0,0 @@ -Import-Package: javax.servlet,\ -org.apache.jackrabbit.webdav.server,\ -org.osgi.framework;version="0.0.0",\ -org.xml.sax;version="0.0.0",\ -org.apache.jackrabbit.webdav.jcr,\ -org.springframework.beans,\ -* diff --git a/org.argeo.server.jackrabbit/build.properties b/org.argeo.server.jackrabbit/build.properties deleted file mode 100644 index 93e080c53..000000000 --- a/org.argeo.server.jackrabbit/build.properties +++ /dev/null @@ -1,2 +0,0 @@ -source.. = src/ -additional.bundles = org.apache.jackrabbit.data diff --git a/org.argeo.server.jackrabbit/pom.xml b/org.argeo.server.jackrabbit/pom.xml deleted file mode 100644 index 4ea6c7172..000000000 --- a/org.argeo.server.jackrabbit/pom.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - 4.0.0 - - org.argeo.commons - argeo-commons - 2.1.14-SNAPSHOT - .. - - org.argeo.server.jackrabbit - Commons Server Jackrabbit - - - org.argeo.commons - org.argeo.util - 2.1.14-SNAPSHOT - - - org.argeo.commons - org.argeo.server.jcr - 2.1.14-SNAPSHOT - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitAuthorizations.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitAuthorizations.java deleted file mode 100644 index e880b6700..000000000 --- a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitAuthorizations.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.jackrabbit; - -import java.security.Principal; -import java.util.Arrays; -import java.util.List; - -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.api.JackrabbitSession; -import org.apache.jackrabbit.api.security.user.Authorizable; -import org.apache.jackrabbit.api.security.user.UserManager; -import org.argeo.ArgeoException; -import org.argeo.jcr.security.JcrAuthorizations; - -/** Apply authorizations to a Jackrabbit repository. */ -public class JackrabbitAuthorizations extends JcrAuthorizations { - private final static Log log = LogFactory - .getLog(JackrabbitAuthorizations.class); - - private List groupPrefixes = Arrays - .asList(new String[] { "ROLE_" });// new ArrayList(); - - @Override - protected Principal getOrCreatePrincipal(Session session, - String principalName) throws RepositoryException { - UserManager um = ((JackrabbitSession) session).getUserManager(); - synchronized (um) { - Authorizable authorizable = um.getAuthorizable(principalName); - if (authorizable == null) { - groupPrefixes: for (String groupPrefix : groupPrefixes) { - if (principalName.startsWith(groupPrefix)) { - authorizable = um.createGroup(principalName); - log.info("Created group " + principalName); - break groupPrefixes; - } - } - if (authorizable == null) - throw new ArgeoException("Authorizable " + principalName - + " not found"); - } - return authorizable.getPrincipal(); - } - } - - public void setGroupPrefixes(List groupsToCreate) { - this.groupPrefixes = groupsToCreate; - } -} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitContainer.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitContainer.java deleted file mode 100644 index 82d58fb31..000000000 --- a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitContainer.java +++ /dev/null @@ -1,374 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.jackrabbit; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashSet; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.TreeSet; -import java.util.UUID; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.api.JackrabbitRepository; -import org.apache.jackrabbit.core.RepositoryImpl; -import org.apache.jackrabbit.core.config.RepositoryConfig; -import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.MaintainedRepository; -import org.springframework.core.io.Resource; -import org.springframework.util.SystemPropertyUtils; -import org.xml.sax.InputSource; - -/** - * Wrapper around a Jackrabbit repository which allows to configure it in Spring - * and expose it as a {@link Repository}. - */ -public class JackrabbitContainer extends JackrabbitWrapper implements - MaintainedRepository { - private final static Log log = LogFactory.getLog(JackrabbitContainer.class); - - // local - private Resource configuration; - - private Resource variables; - - private RepositoryConfig repositoryConfig; - private File homeDirectory; - private Boolean inMemory = false; - - /** Migrations to execute (if not already done) */ - private Set dataModelMigrations = new HashSet(); - - /** Straight (non spring) values */ - private Properties configurationProperties; - private InputSource configurationXml; - - /** - * Empty constructor, {@link #init()} should be called after properties have - * been set - */ - public JackrabbitContainer() { - } - - public void init() { - long begin = System.currentTimeMillis(); - - if (getRepository() != null) - throw new ArgeoException( - "Cannot be used to wrap another repository"); - Repository repository = createJackrabbitRepository(); - super.setRepository(repository); - - // migrate if needed - migrate(); - - // apply new CND files after migration - prepareDataModel(); - - double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; - if (log.isDebugEnabled()) - log.debug("Initialized JCR repository wrapper in " + duration - + " s"); - } - - /** Actually creates the new repository. */ - protected Repository createJackrabbitRepository() { - long begin = System.currentTimeMillis(); - InputStream configurationIn = null; - Repository repository; - try { - // temporary - if (inMemory && getHomeDirectory().exists()) { - FileUtils.deleteDirectory(getHomeDirectory()); - log.warn("Deleted Jackrabbit home directory " - + getHomeDirectory()); - } - - // process configuration file - Properties vars = getConfigurationProperties(); - vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, - getHomeDirectory().getCanonicalPath()); - InputSource is; - if (configurationXml != null) - is = configurationXml; - else { - configurationIn = readConfiguration(); - is = new InputSource(configurationIn); - } - repositoryConfig = RepositoryConfig.create(is, vars); - - // - // Actual repository creation - // - repository = RepositoryImpl.create(repositoryConfig); - - double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; - if (log.isTraceEnabled()) - log.trace("Created Jackrabbit repository in " + duration - + " s, home: " + getHomeDirectory()); - - return repository; - } catch (Exception e) { - throw new ArgeoException("Cannot create Jackrabbit repository " - + getHomeDirectory(), e); - } finally { - IOUtils.closeQuietly(configurationIn); - } - } - - /** Lazy init. */ - protected File getHomeDirectory() { - try { - if (homeDirectory == null) { - if (inMemory) { - homeDirectory = new File( - System.getProperty("java.io.tmpdir") - + File.separator - + System.getProperty("user.name") - + File.separator + "jackrabbit-" - + UUID.randomUUID()); - homeDirectory.mkdirs(); - // will it work if directory is not empty?? - homeDirectory.deleteOnExit(); - } - } - - return homeDirectory.getCanonicalFile(); - } catch (IOException e) { - throw new ArgeoException("Cannot get canonical file for " - + homeDirectory, e); - } - } - - /** Executes migrations, if needed. */ - protected void migrate() { - // No migration to perform - if (dataModelMigrations.size() == 0) - return; - - Boolean restartAndClearCaches = false; - - // migrate data - Session session = null; - try { - session = login(); - for (JackrabbitDataModelMigration dataModelMigration : new TreeSet( - dataModelMigrations)) { - if (dataModelMigration.migrate(session)) { - restartAndClearCaches = true; - } - } - } catch (ArgeoException e) { - throw e; - } catch (Exception e) { - throw new ArgeoException("Cannot migrate", e); - } finally { - JcrUtils.logoutQuietly(session); - } - - // restart repository - if (restartAndClearCaches) { - Repository repository = getRepository(); - if (repository instanceof RepositoryImpl) { - JackrabbitDataModelMigration - .clearRepositoryCaches(((RepositoryImpl) repository) - .getConfig()); - } - ((JackrabbitRepository) repository).shutdown(); - createJackrabbitRepository(); - } - - // set data model version - try { - session = login(); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot login to migrated repository", e); - } - - for (JackrabbitDataModelMigration dataModelMigration : new TreeSet( - dataModelMigrations)) { - try { - if (session.itemExists(dataModelMigration - .getDataModelNodePath())) { - Node dataModelNode = session.getNode(dataModelMigration - .getDataModelNodePath()); - dataModelNode.setProperty( - ArgeoNames.ARGEO_DATA_MODEL_VERSION, - dataModelMigration.getTargetVersion()); - session.save(); - } - } catch (Exception e) { - log.error("Cannot set model version", e); - } - } - JcrUtils.logoutQuietly(session); - - } - - /** Shutdown the repository */ - public void destroy() throws Exception { - Repository repository = getRepository(); - if (repository != null && repository instanceof RepositoryImpl) { - long begin = System.currentTimeMillis(); - ((RepositoryImpl) repository).shutdown(); - if (inMemory) - if (getHomeDirectory().exists()) { - FileUtils.deleteDirectory(getHomeDirectory()); - if (log.isDebugEnabled()) - log.debug("Deleted Jackrabbit home directory " - + getHomeDirectory()); - } - double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; - log.info("Destroyed Jackrabbit repository in " + duration - + " s, home: " + getHomeDirectory()); - } - repository = null; - } - - public void dispose() { - throw new IllegalArgumentException( - "Call destroy() method instead of dispose()"); - } - - /* - * UTILITIES - */ - /** - * Reads the configuration which will initialize a {@link RepositoryConfig}. - */ - protected InputStream readConfiguration() { - try { - return configuration != null ? configuration.getInputStream() - : null; - } catch (IOException e) { - throw new ArgeoException("Cannot read Jackrabbit configuration " - + configuration, e); - } - } - - /** - * Reads the variables which will initialize a {@link Properties}. Returns - * null by default, to be overridden. - * - * @return a new stream or null if no variables available - */ - protected InputStream readVariables() { - try { - return variables != null ? variables.getInputStream() : null; - } catch (IOException e) { - throw new ArgeoException("Cannot read Jackrabbit variables " - + variables, e); - } - } - - /** - * Resolves ${} placeholders in the provided string. Based on system - * properties if no map is provided. - */ - protected String resolvePlaceholders(String string, - Map variables) { - return SystemPropertyUtils.resolvePlaceholders(string); - } - - /** Generates the properties to use in the configuration. */ - protected Properties getConfigurationProperties() { - if (configurationProperties != null) - return configurationProperties; - - InputStream propsIn = null; - Properties vars; - try { - vars = new Properties(); - propsIn = readVariables(); - if (propsIn != null) { - vars.load(propsIn); - } - // resolve system properties - for (Object key : vars.keySet()) { - // TODO: implement a smarter mechanism to resolve nested ${} - String newValue = resolvePlaceholders( - vars.getProperty(key.toString()), null); - vars.put(key, newValue); - } - // override with system properties - vars.putAll(System.getProperties()); - - if (log.isTraceEnabled()) { - log.trace("Jackrabbit config variables:"); - for (Object key : new TreeSet(vars.keySet())) - log.trace(key + "=" + vars.getProperty(key.toString())); - } - - } catch (IOException e) { - throw new ArgeoException("Cannot read configuration properties", e); - } finally { - IOUtils.closeQuietly(propsIn); - } - return vars; - } - - /* - * FIELDS ACCESS - */ - - public void setHomeDirectory(File homeDirectory) { - this.homeDirectory = homeDirectory; - } - - public void setInMemory(Boolean inMemory) { - this.inMemory = inMemory; - } - - public void setRepository(Repository repository) { - throw new ArgeoException("Cannot be used to wrap another repository"); - } - - public void setDataModelMigrations( - Set dataModelMigrations) { - this.dataModelMigrations = dataModelMigrations; - } - - public void setVariables(Resource variables) { - this.variables = variables; - } - - public void setConfiguration(Resource configuration) { - this.configuration = configuration; - } - - public void setConfigurationProperties(Properties configurationProperties) { - this.configurationProperties = configurationProperties; - } - - public void setConfigurationXml(InputSource configurationXml) { - this.configurationXml = configurationXml; - } - -} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java deleted file mode 100644 index 401b34df6..000000000 --- a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.jackrabbit; - -import java.io.InputStreamReader; -import java.io.Reader; - -import javax.jcr.Node; -import javax.jcr.Session; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.commons.cnd.CndImporter; -import org.apache.jackrabbit.core.config.RepositoryConfig; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.JcrCallback; -import org.argeo.jcr.JcrUtils; -import org.springframework.core.io.Resource; - -/** Migrate the data in a Jackrabbit repository. */ -public class JackrabbitDataModelMigration implements - Comparable { - private final static Log log = LogFactory - .getLog(JackrabbitDataModelMigration.class); - - private String dataModelNodePath; - private String targetVersion; - private Resource migrationCnd; - private JcrCallback dataModification; - - /** - * Expects an already started repository with the old data model to migrate. - * Expects to be run with admin rights (Repository.login() will be used). - * - * @return true if a migration was performed and the repository needs to be - * restarted and its caches cleared. - */ - public Boolean migrate(Session session) { - long begin = System.currentTimeMillis(); - Reader reader = null; - try { - // check if already migrated - if (!session.itemExists(dataModelNodePath)) { - log.warn("Node " + dataModelNodePath - + " does not exist: nothing to migrate."); - return false; - } - Node dataModelNode = session.getNode(dataModelNodePath); - if (dataModelNode.hasProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION)) { - String currentVersion = dataModelNode.getProperty( - ArgeoNames.ARGEO_DATA_MODEL_VERSION).getString(); - if (compareVersions(currentVersion, targetVersion) >= 0) { - log.info("Data model at version " + currentVersion - + ", no need to migrate."); - return false; - } - } - - // apply transitional CND - if (migrationCnd != null) { - reader = new InputStreamReader(migrationCnd.getInputStream()); - CndImporter.registerNodeTypes(reader, session, true); - session.save(); - log.info("Registered migration node types from " + migrationCnd); - } - - // modify data - dataModification.execute(session); - - // apply changes - session.save(); - - long duration = System.currentTimeMillis() - begin; - log.info("Migration of data model " + dataModelNodePath + " to " - + targetVersion + " performed in " + duration + "ms"); - return true; - } catch (Exception e) { - JcrUtils.discardQuietly(session); - throw new ArgeoException("Migration of data model " - + dataModelNodePath + " to " + targetVersion + " failed.", - e); - } finally { - JcrUtils.logoutQuietly(session); - IOUtils.closeQuietly(reader); - } - } - - protected static int compareVersions(String version1, String version2) { - // TODO do a proper version analysis and comparison - return version1.compareTo(version2); - } - - /** To be called on a stopped repository. */ - public static void clearRepositoryCaches(RepositoryConfig repositoryConfig) { - try { - String customeNodeTypesPath = "/nodetypes/custom_nodetypes.xml"; - repositoryConfig.getFileSystem().deleteFile(customeNodeTypesPath); - if (log.isDebugEnabled()) - log.debug("Cleared " + customeNodeTypesPath); - } catch (Exception e) { - throw new ArgeoException("Cannot clear caches", e); - } - - // File customNodeTypes = new File(home.getPath() - // + "/repository/nodetypes/custom_nodetypes.xml"); - // if (customNodeTypes.exists()) { - // customNodeTypes.delete(); - // if (log.isDebugEnabled()) - // log.debug("Cleared " + customNodeTypes); - // } else { - // log.warn("File " + customNodeTypes + " not found."); - // } - } - - /* - * FOR USE IN (SORTED) SETS - */ - - public int compareTo(JackrabbitDataModelMigration dataModelMigration) { - // TODO make ordering smarter - if (dataModelNodePath.equals(dataModelMigration.dataModelNodePath)) - return compareVersions(targetVersion, - dataModelMigration.targetVersion); - else - return dataModelNodePath - .compareTo(dataModelMigration.dataModelNodePath); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof JackrabbitDataModelMigration)) - return false; - JackrabbitDataModelMigration dataModelMigration = (JackrabbitDataModelMigration) obj; - return dataModelNodePath.equals(dataModelMigration.dataModelNodePath) - && targetVersion.equals(dataModelMigration.targetVersion); - } - - @Override - public int hashCode() { - return targetVersion.hashCode(); - } - - public void setDataModelNodePath(String dataModelNodePath) { - this.dataModelNodePath = dataModelNodePath; - } - - public void setTargetVersion(String targetVersion) { - this.targetVersion = targetVersion; - } - - public void setMigrationCnd(Resource migrationCnd) { - this.migrationCnd = migrationCnd; - } - - public void setDataModification(JcrCallback dataModification) { - this.dataModification = dataModification; - } - - public String getDataModelNodePath() { - return dataModelNodePath; - } - - public String getTargetVersion() { - return targetVersion; - } - -} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java deleted file mode 100644 index d64bb5e68..000000000 --- a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.jackrabbit; - -import java.io.File; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.RepositoryFactory; -import javax.jcr.Session; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.commons.JcrUtils; -import org.apache.jackrabbit.core.RepositoryImpl; -import org.apache.jackrabbit.core.config.RepositoryConfig; -import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; -import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.DefaultRepositoryFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.xml.sax.InputSource; - -/** - * Repository factory which can create new repositories and access remote - * Jackrabbit repositories - */ -public class JackrabbitRepositoryFactory extends DefaultRepositoryFactory - implements RepositoryFactory, ArgeoJcrConstants { - - private final static Log log = LogFactory - .getLog(JackrabbitRepositoryFactory.class); - - private Resource fileRepositoryConfiguration = new ClassPathResource( - "/org/argeo/jackrabbit/repository-h2.xml"); - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Repository getRepository(Map parameters) throws RepositoryException { - // check if can be found by alias - Repository repository = super.getRepository(parameters); - if (repository != null) - return repository; - - // check if remote - String uri = null; - if (parameters.containsKey(JCR_REPOSITORY_URI)) - uri = parameters.get(JCR_REPOSITORY_URI).toString(); - else if (parameters.containsKey(JcrUtils.REPOSITORY_URI)) - uri = parameters.get(JcrUtils.REPOSITORY_URI).toString(); - - if (uri != null) { - if (uri.startsWith("http"))// http, https - repository = createRemoteRepository(uri); - else if (uri.startsWith("file"))// http, https - repository = createFileRepository(uri, parameters); - else if (uri.startsWith("vm")) { - log.warn("URI " - + uri - + " should have been managed by generic JCR repository factory"); - repository = getRepositoryByAlias(getAliasFromURI(uri)); - } - } - - // publish under alias - if (parameters.containsKey(JCR_REPOSITORY_ALIAS)) { - Properties properties = new Properties(); - properties.putAll(parameters); - String alias = parameters.get(JCR_REPOSITORY_ALIAS).toString(); - publish(alias, repository, properties); - log.info("Registered JCR repository under alias '" + alias - + "' with properties " + properties); - } - - return repository; - } - - protected Repository createRemoteRepository(String uri) - throws RepositoryException { - Map params = new HashMap(); - params.put(JcrUtils.REPOSITORY_URI, uri); - Repository repository = new Jcr2davRepositoryFactory() - .getRepository(params); - if (repository == null) - throw new ArgeoException("Remote Davex repository " + uri - + " not found"); - log.info("Initialized remote Jackrabbit repository from uri " + uri); - return repository; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - protected Repository createFileRepository(final String uri, Map parameters) - throws RepositoryException { - InputStream configurationIn = null; - try { - Properties vars = new Properties(); - vars.putAll(parameters); - String dirPath = uri.substring("file:".length()); - File homeDir = new File(dirPath); - if (homeDir.exists() && !homeDir.isDirectory()) - throw new ArgeoException("Repository home " + dirPath - + " is not a directory"); - if (!homeDir.exists()) - homeDir.mkdirs(); - configurationIn = fileRepositoryConfiguration.getInputStream(); - vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, - homeDir.getCanonicalPath()); - RepositoryConfig repositoryConfig = RepositoryConfig.create( - new InputSource(configurationIn), vars); - - // TransientRepository repository = new - // TransientRepository(repositoryConfig); - final RepositoryImpl repository = RepositoryImpl - .create(repositoryConfig); - Session session = repository.login(); - // FIXME make it generic - org.argeo.jcr.JcrUtils.addPrivilege(session, "/", "ROLE_ADMIN", - "jcr:all"); - org.argeo.jcr.JcrUtils.logoutQuietly(session); - Runtime.getRuntime().addShutdownHook( - new Thread("Clean JCR repository " + uri) { - public void run() { - repository.shutdown(); - log.info("Destroyed repository " + uri); - } - }); - log.info("Initialized file Jackrabbit repository from uri " + uri); - return repository; - } catch (Exception e) { - throw new ArgeoException("Cannot create repository " + uri, e); - } finally { - IOUtils.closeQuietly(configurationIn); - } - } - - /** - * Called after the repository has been initialised. Does nothing by - * default. - */ - @SuppressWarnings("rawtypes") - protected void postInitialization(Repository repository, Map parameters) { - - } - - public void setFileRepositoryConfiguration( - Resource fileRepositoryConfiguration) { - this.fileRepositoryConfiguration = fileRepositoryConfiguration; - } - -} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitWrapper.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitWrapper.java deleted file mode 100644 index 53a9ff1e2..000000000 --- a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/JackrabbitWrapper.java +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.jackrabbit; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.jcr.Credentials; -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Repository; -import javax.jcr.Session; -import javax.jcr.nodetype.NodeType; - -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.commons.NamespaceHelper; -import org.apache.jackrabbit.commons.cnd.CndImporter; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.ArgeoTypes; -import org.argeo.jcr.JcrRepositoryWrapper; -import org.argeo.jcr.JcrUtils; -import org.argeo.util.security.DigestUtils; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.service.packageadmin.ExportedPackage; -import org.osgi.service.packageadmin.PackageAdmin; -import org.springframework.context.ResourceLoaderAware; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; - -/** - * Wrapper around a Jackrabbit repository which allows to simplify configuration - * and intercept some actions. It exposes itself as a {@link Repository}. - */ -public class JackrabbitWrapper extends JcrRepositoryWrapper implements - ResourceLoaderAware { - private final static Log log = LogFactory.getLog(JackrabbitWrapper.class); - private final static String DIGEST_ALGORITHM = "MD5"; - - // local - private ResourceLoader resourceLoader; - - // data model - /** Node type definitions in CND format */ - private List cndFiles = new ArrayList(); - /** - * Always import CNDs. Useful during development of new data models. In - * production, explicit migration processes should be used. - */ - private Boolean forceCndImport = true; - - /** Namespaces to register: key is prefix, value namespace */ - private Map namespaces = new HashMap(); - - private BundleContext bundleContext; - - /** - * Explicitly set admin credentials used in initialization. Useful for - * testing, in real applications authentication is rather dealt with - * externally - */ - private Credentials adminCredentials = null; - - /** - * Empty constructor, {@link #init()} should be called after properties have - * been set - */ - public JackrabbitWrapper() { - } - - @Override - public void init() { - prepareDataModel(); - } - - /* - * DATA MODEL - */ - - /** - * Import declared node type definitions and register namespaces. Tries to - * update the node definitions if they have changed. In case of failures an - * error will be logged but no exception will be thrown. - */ - protected void prepareDataModel() { - if ((cndFiles == null || cndFiles.size() == 0) - && (namespaces == null || namespaces.size() == 0)) - return; - - Session session = null; - try { - session = login(adminCredentials); - // register namespaces - if (namespaces.size() > 0) { - NamespaceHelper namespaceHelper = new NamespaceHelper(session); - namespaceHelper.registerNamespaces(namespaces); - } - - // load CND files from classpath or as URL - for (String resUrl : cndFiles) { - processCndFile(session, resUrl); - } - } catch (Exception e) { - JcrUtils.discardQuietly(session); - throw new ArgeoException("Cannot import node type definitions " - + cndFiles, e); - } finally { - JcrUtils.logoutQuietly(session); - } - - } - - protected void processCndFile(Session session, String resUrl) { - Reader reader = null; - try { - // check existing data model nodes - new NamespaceHelper(session).registerNamespace(ArgeoNames.ARGEO, - ArgeoNames.ARGEO_NAMESPACE); - if (!session.itemExists(ArgeoJcrConstants.DATA_MODELS_BASE_PATH)) - JcrUtils.mkdirs(session, - ArgeoJcrConstants.DATA_MODELS_BASE_PATH); - Node dataModels = session - .getNode(ArgeoJcrConstants.DATA_MODELS_BASE_PATH); - NodeIterator it = dataModels.getNodes(); - Node dataModel = null; - while (it.hasNext()) { - Node node = it.nextNode(); - if (node.getProperty(ArgeoNames.ARGEO_URI).getString() - .equals(resUrl)) { - dataModel = node; - break; - } - } - - byte[] cndContent = readCndContent(resUrl); - String newDigest = DigestUtils.digest(DIGEST_ALGORITHM, cndContent); - Bundle bundle = findDataModelBundle(resUrl); - - String currentVersion = null; - if (dataModel != null) { - currentVersion = dataModel.getProperty( - ArgeoNames.ARGEO_DATA_MODEL_VERSION).getString(); - if (dataModel.hasNode(Node.JCR_CONTENT)) { - String oldDigest = JcrUtils.checksumFile(dataModel, - DIGEST_ALGORITHM); - if (oldDigest.equals(newDigest)) { - if (log.isDebugEnabled()) - log.debug("Data model " + resUrl - + " hasn't changed, keeping version " - + currentVersion); - return; - } - } - } - - if (dataModel != null && !forceCndImport) { - log.info("Data model " - + resUrl - + " has changed since version " - + currentVersion - + (bundle != null ? ": version " + bundle.getVersion() - + ", bundle " + bundle.getSymbolicName() : "")); - return; - } - - reader = new InputStreamReader(new ByteArrayInputStream(cndContent)); - // actually imports the CND - try { - CndImporter.registerNodeTypes(reader, session, true); - } catch (Exception e) { - log.error("Cannot import data model " + resUrl, e); - return; - } - - if (dataModel != null && !dataModel.isNodeType(NodeType.NT_FILE)) { - dataModel.remove(); - dataModel = null; - } - - // FIXME: what if argeo.cnd would not be the first called on - // a new repo? argeo:dataModel would not be found - String fileName = FilenameUtils.getName(resUrl); - if (dataModel == null) { - dataModel = dataModels.addNode(fileName, NodeType.NT_FILE); - dataModel.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE); - dataModel.addMixin(ArgeoTypes.ARGEO_DATA_MODEL); - dataModel.setProperty(ArgeoNames.ARGEO_URI, resUrl); - } else { - session.getWorkspace().getVersionManager() - .checkout(dataModel.getPath()); - } - if (bundle != null) - dataModel.setProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION, - bundle.getVersion().toString()); - else - dataModel.setProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION, - "0.0.0"); - JcrUtils.copyBytesAsFile(dataModel.getParent(), fileName, - cndContent); - JcrUtils.updateLastModified(dataModel); - session.save(); - session.getWorkspace().getVersionManager() - .checkin(dataModel.getPath()); - - if (currentVersion == null) - log.info("Data model " - + resUrl - + (bundle != null ? ", version " + bundle.getVersion() - + ", bundle " + bundle.getSymbolicName() : "")); - else - log.info("Data model " - + resUrl - + " updated from version " - + currentVersion - + (bundle != null ? ", version " + bundle.getVersion() - + ", bundle " + bundle.getSymbolicName() : "")); - } catch (Exception e) { - throw new ArgeoException("Cannot process data model " + resUrl, e); - } finally { - IOUtils.closeQuietly(reader); - } - } - - protected byte[] readCndContent(String resUrl) { - InputStream in = null; - try { - boolean classpath; - // normalize URL - if (bundleContext != null && resUrl.startsWith("classpath:")) { - resUrl = resUrl.substring("classpath:".length()); - classpath = true; - } else if (resUrl.indexOf(':') < 0) { - if (!resUrl.startsWith("/")) { - resUrl = "/" + resUrl; - log.warn("Classpath should start with '/'"); - } - classpath = true; - } else { - classpath = false; - } - - URL url = null; - if (classpath) { - if (bundleContext != null) { - Bundle currentBundle = bundleContext.getBundle(); - url = currentBundle.getResource(resUrl); - } else { - resUrl = "classpath:" + resUrl; - url = null; - } - } else if (!resUrl.startsWith("classpath:")) { - url = new URL(resUrl); - } - - if (url != null) { - in = url.openStream(); - } else if (resourceLoader != null) { - Resource res = resourceLoader.getResource(resUrl); - in = res.getInputStream(); - url = res.getURL(); - } else { - throw new ArgeoException("No " + resUrl + " in the classpath," - + " make sure the containing" + " package is visible."); - } - - return IOUtils.toByteArray(in); - } catch (Exception e) { - throw new ArgeoException("Cannot read CND from " + resUrl, e); - } finally { - IOUtils.closeQuietly(in); - } - } - - /* - * REPOSITORY INTERCEPTOR - */ - - /* - * UTILITIES - */ - /** Find which OSGi bundle provided the data model resource */ - protected Bundle findDataModelBundle(String resUrl) { - if (bundleContext == null) - return null; - - if (resUrl.startsWith("/")) - resUrl = resUrl.substring(1); - String pkg = resUrl.substring(0, resUrl.lastIndexOf('/')).replace('/', - '.'); - ServiceReference paSr = bundleContext - .getServiceReference(PackageAdmin.class.getName()); - PackageAdmin packageAdmin = (PackageAdmin) bundleContext - .getService(paSr); - - // find exported package - ExportedPackage exportedPackage = null; - ExportedPackage[] exportedPackages = packageAdmin - .getExportedPackages(pkg); - if (exportedPackages == null) - throw new ArgeoException("No exported package found for " + pkg); - for (ExportedPackage ep : exportedPackages) { - for (Bundle b : ep.getImportingBundles()) { - if (b.getBundleId() == bundleContext.getBundle().getBundleId()) { - exportedPackage = ep; - break; - } - } - } - - Bundle exportingBundle = null; - if (exportedPackage != null) { - exportingBundle = exportedPackage.getExportingBundle(); - } else { - // assume this is in the same bundle - exportingBundle = bundleContext.getBundle(); - // throw new ArgeoException("No OSGi exporting package found for " - // + resUrl); - } - return exportingBundle; - } - - /* - * FIELDS ACCESS - */ - public void setNamespaces(Map namespaces) { - this.namespaces = namespaces; - } - - public void setCndFiles(List cndFiles) { - this.cndFiles = cndFiles; - } - - public void setBundleContext(BundleContext bundleContext) { - this.bundleContext = bundleContext; - } - - protected BundleContext getBundleContext() { - return bundleContext; - } - - public void setForceCndImport(Boolean forceCndUpdate) { - this.forceCndImport = forceCndUpdate; - } - - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - - public void setAdminCredentials(Credentials adminCredentials) { - this.adminCredentials = adminCredentials; - } - -} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java deleted file mode 100644 index b28699e60..000000000 --- a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.jackrabbit; - -import java.util.Hashtable; -import java.util.Properties; - -import javax.jcr.Repository; - -import org.osgi.framework.BundleContext; - -/** - * OSGi-aware Jackrabbit repository factory which can retrieve/publish - * {@link Repository} as OSGi services. - */ -public class OsgiJackrabbitRepositoryFactory extends - JackrabbitRepositoryFactory { - private BundleContext bundleContext; - - protected void publish(String alias, Repository repository, - Properties properties) { - if (bundleContext != null) { - // do not modify reference - Hashtable props = new Hashtable(); - props.putAll(props); - props.put(JCR_REPOSITORY_ALIAS, alias); - bundleContext.registerService(Repository.class.getName(), - repository, props); - } - } - - public void setBundleContext(BundleContext bundleContext) { - this.bundleContext = bundleContext; - } - -} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-fs.xml b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-fs.xml deleted file mode 100644 index 609fc8b33..000000000 --- a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-fs.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-h2.xml b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-h2.xml deleted file mode 100644 index b6a92528a..000000000 --- a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-h2.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-memory.xml b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-memory.xml deleted file mode 100644 index e552c33a7..000000000 --- a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/repository-memory.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/servlet/OpenInViewSessionProvider.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/servlet/OpenInViewSessionProvider.java deleted file mode 100644 index 519a21840..000000000 --- a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/servlet/OpenInViewSessionProvider.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.jackrabbit.servlet; - -import java.io.Serializable; - -import javax.jcr.LoginException; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.server.SessionProvider; -import org.argeo.jcr.JcrUtils; - -/** - * Implements an open session in view patter: a new JCR session is created for - * each request - */ -public class OpenInViewSessionProvider implements SessionProvider, Serializable { - private static final long serialVersionUID = 2270957712453841368L; - - private final static Log log = LogFactory - .getLog(OpenInViewSessionProvider.class); - - public Session getSession(HttpServletRequest request, Repository rep, - String workspace) throws LoginException, ServletException, - RepositoryException { - return login(request, rep, workspace); - } - - protected Session login(HttpServletRequest request, Repository repository, - String workspace) throws RepositoryException { - if (log.isTraceEnabled()) - log.trace("Login to workspace " - + (workspace == null ? "" : workspace) - + " in web session " + request.getSession().getId()); - return repository.login(workspace); - } - - public void releaseSession(Session session) { - JcrUtils.logoutQuietly(session); - if (log.isTraceEnabled()) - log.trace("Logged out remote JCR session " + session); - } - - public void init() { - } - - public void destroy() { - } - -} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/servlet/RemotingServlet.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/servlet/RemotingServlet.java deleted file mode 100644 index 01bbb355d..000000000 --- a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/servlet/RemotingServlet.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.jackrabbit.servlet; - -import javax.jcr.Repository; - -import org.apache.jackrabbit.server.SessionProvider; -import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet; - -/** Provides remote access to a JCR repository */ -public class RemotingServlet extends JcrRemotingServlet { - public final static String INIT_PARAM_RESOURCE_PATH_PREFIX = JcrRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX; - public final static String INIT_PARAM_HOME = JcrRemotingServlet.INIT_PARAM_HOME; - public final static String INIT_PARAM_TMP_DIRECTORY = JcrRemotingServlet.INIT_PARAM_TMP_DIRECTORY; - - private static final long serialVersionUID = 3131835511468341309L; - - private final Repository repository; - private final SessionProvider sessionProvider; - - public RemotingServlet(Repository repository, - SessionProvider sessionProvider) { - this.repository = repository; - this.sessionProvider = sessionProvider; - } - - @Override - protected Repository getRepository() { - return repository; - } - - @Override - protected SessionProvider getSessionProvider() { - return sessionProvider; - } - -} diff --git a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/servlet/WebdavServlet.java b/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/servlet/WebdavServlet.java deleted file mode 100644 index c2346f00e..000000000 --- a/org.argeo.server.jackrabbit/src/org/argeo/jackrabbit/servlet/WebdavServlet.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.argeo.jackrabbit.servlet; - -import java.io.IOException; - -import javax.jcr.Repository; -import javax.servlet.ServletException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.server.SessionProvider; -import org.apache.jackrabbit.webdav.DavException; -import org.apache.jackrabbit.webdav.DavResource; -import org.apache.jackrabbit.webdav.WebdavRequest; -import org.apache.jackrabbit.webdav.WebdavResponse; -import org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet; - -/** WebDav servlet whose repository is injected */ -public class WebdavServlet extends SimpleWebdavServlet { - public final static String INIT_PARAM_RESOURCE_CONFIG = SimpleWebdavServlet.INIT_PARAM_RESOURCE_CONFIG; - public final static String INIT_PARAM_RESOURCE_PATH_PREFIX = SimpleWebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX; - - private static final long serialVersionUID = -369787931175177080L; - - private final static Log log = LogFactory.getLog(WebdavServlet.class); - - private final Repository repository; - - public WebdavServlet(Repository repository, SessionProvider sessionProvider) { - this.repository = repository; - setSessionProvider(sessionProvider); - } - - public Repository getRepository() { - return repository; - } - - @Override - protected boolean execute(WebdavRequest request, WebdavResponse response, - int method, DavResource resource) throws ServletException, - IOException, DavException { - if (log.isTraceEnabled()) - log.trace(request.getMethod() + "\t" + request.getPathInfo()); - boolean res = super.execute(request, response, method, resource); - return res; - } - -} diff --git a/org.argeo.server.jcr/bnd.bnd b/org.argeo.server.jcr/bnd.bnd index 2b0bd1b2c..d0385e232 100644 --- a/org.argeo.server.jcr/bnd.bnd +++ b/org.argeo.server.jcr/bnd.bnd @@ -3,4 +3,8 @@ org.xml.sax;version="0.0.0",\ org.springframework.core;resolution:=optional,\ org.springframework.core.io;resolution:=optional,\ org.springframework.*;resolution:=optional,\ +org.apache.jackrabbit.*;resolution:=optional,\ +org.apache.jackrabbit.webdav.jcr;resolution:=optional,\ +org.apache.jackrabbit.webdav.server;resolution:=optional,\ * +Export-Package: org.argeo.jcr.*, org.argeo.jackrabbit.* \ No newline at end of file diff --git a/org.argeo.server.jcr/build.properties b/org.argeo.server.jcr/build.properties index bea936651..1d2423681 100644 --- a/org.argeo.server.jcr/build.properties +++ b/org.argeo.server.jcr/build.properties @@ -1,7 +1,6 @@ source.. = src/,\ ext/test/ -output.. = bin/,\ - bin/test-classes/ +output.. = bin/ bin.includes = META-INF/,\ . additional.bundles = org.junit,\ @@ -12,4 +11,3 @@ additional.bundles = org.junit,\ org.apache.jackrabbit.jcr.commons,\ org.apache.jackrabbit.spi,\ org.apache.jackrabbit.spi.commons - diff --git a/org.argeo.server.jcr/pom.xml b/org.argeo.server.jcr/pom.xml index 790c7dfee..95e49a843 100644 --- a/org.argeo.server.jcr/pom.xml +++ b/org.argeo.server.jcr/pom.xml @@ -7,103 +7,12 @@ .. org.argeo.server.jcr - Commons Server JCR - - - - org.argeo.maven.plugins - maven-argeo-osgi-plugin - - true - true - - -clean - - - - XXX - - - - - + Commons JCR org.argeo.commons org.argeo.util 2.1.14-SNAPSHOT - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitAuthorizations.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitAuthorizations.java new file mode 100644 index 000000000..e880b6700 --- /dev/null +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitAuthorizations.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.jackrabbit; + +import java.security.Principal; +import java.util.Arrays; +import java.util.List; + +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.api.JackrabbitSession; +import org.apache.jackrabbit.api.security.user.Authorizable; +import org.apache.jackrabbit.api.security.user.UserManager; +import org.argeo.ArgeoException; +import org.argeo.jcr.security.JcrAuthorizations; + +/** Apply authorizations to a Jackrabbit repository. */ +public class JackrabbitAuthorizations extends JcrAuthorizations { + private final static Log log = LogFactory + .getLog(JackrabbitAuthorizations.class); + + private List groupPrefixes = Arrays + .asList(new String[] { "ROLE_" });// new ArrayList(); + + @Override + protected Principal getOrCreatePrincipal(Session session, + String principalName) throws RepositoryException { + UserManager um = ((JackrabbitSession) session).getUserManager(); + synchronized (um) { + Authorizable authorizable = um.getAuthorizable(principalName); + if (authorizable == null) { + groupPrefixes: for (String groupPrefix : groupPrefixes) { + if (principalName.startsWith(groupPrefix)) { + authorizable = um.createGroup(principalName); + log.info("Created group " + principalName); + break groupPrefixes; + } + } + if (authorizable == null) + throw new ArgeoException("Authorizable " + principalName + + " not found"); + } + return authorizable.getPrincipal(); + } + } + + public void setGroupPrefixes(List groupsToCreate) { + this.groupPrefixes = groupsToCreate; + } +} diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitContainer.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitContainer.java new file mode 100644 index 000000000..82d58fb31 --- /dev/null +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitContainer.java @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.jackrabbit; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; +import java.util.UUID; + +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.api.JackrabbitRepository; +import org.apache.jackrabbit.core.RepositoryImpl; +import org.apache.jackrabbit.core.config.RepositoryConfig; +import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.MaintainedRepository; +import org.springframework.core.io.Resource; +import org.springframework.util.SystemPropertyUtils; +import org.xml.sax.InputSource; + +/** + * Wrapper around a Jackrabbit repository which allows to configure it in Spring + * and expose it as a {@link Repository}. + */ +public class JackrabbitContainer extends JackrabbitWrapper implements + MaintainedRepository { + private final static Log log = LogFactory.getLog(JackrabbitContainer.class); + + // local + private Resource configuration; + + private Resource variables; + + private RepositoryConfig repositoryConfig; + private File homeDirectory; + private Boolean inMemory = false; + + /** Migrations to execute (if not already done) */ + private Set dataModelMigrations = new HashSet(); + + /** Straight (non spring) values */ + private Properties configurationProperties; + private InputSource configurationXml; + + /** + * Empty constructor, {@link #init()} should be called after properties have + * been set + */ + public JackrabbitContainer() { + } + + public void init() { + long begin = System.currentTimeMillis(); + + if (getRepository() != null) + throw new ArgeoException( + "Cannot be used to wrap another repository"); + Repository repository = createJackrabbitRepository(); + super.setRepository(repository); + + // migrate if needed + migrate(); + + // apply new CND files after migration + prepareDataModel(); + + double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; + if (log.isDebugEnabled()) + log.debug("Initialized JCR repository wrapper in " + duration + + " s"); + } + + /** Actually creates the new repository. */ + protected Repository createJackrabbitRepository() { + long begin = System.currentTimeMillis(); + InputStream configurationIn = null; + Repository repository; + try { + // temporary + if (inMemory && getHomeDirectory().exists()) { + FileUtils.deleteDirectory(getHomeDirectory()); + log.warn("Deleted Jackrabbit home directory " + + getHomeDirectory()); + } + + // process configuration file + Properties vars = getConfigurationProperties(); + vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, + getHomeDirectory().getCanonicalPath()); + InputSource is; + if (configurationXml != null) + is = configurationXml; + else { + configurationIn = readConfiguration(); + is = new InputSource(configurationIn); + } + repositoryConfig = RepositoryConfig.create(is, vars); + + // + // Actual repository creation + // + repository = RepositoryImpl.create(repositoryConfig); + + double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; + if (log.isTraceEnabled()) + log.trace("Created Jackrabbit repository in " + duration + + " s, home: " + getHomeDirectory()); + + return repository; + } catch (Exception e) { + throw new ArgeoException("Cannot create Jackrabbit repository " + + getHomeDirectory(), e); + } finally { + IOUtils.closeQuietly(configurationIn); + } + } + + /** Lazy init. */ + protected File getHomeDirectory() { + try { + if (homeDirectory == null) { + if (inMemory) { + homeDirectory = new File( + System.getProperty("java.io.tmpdir") + + File.separator + + System.getProperty("user.name") + + File.separator + "jackrabbit-" + + UUID.randomUUID()); + homeDirectory.mkdirs(); + // will it work if directory is not empty?? + homeDirectory.deleteOnExit(); + } + } + + return homeDirectory.getCanonicalFile(); + } catch (IOException e) { + throw new ArgeoException("Cannot get canonical file for " + + homeDirectory, e); + } + } + + /** Executes migrations, if needed. */ + protected void migrate() { + // No migration to perform + if (dataModelMigrations.size() == 0) + return; + + Boolean restartAndClearCaches = false; + + // migrate data + Session session = null; + try { + session = login(); + for (JackrabbitDataModelMigration dataModelMigration : new TreeSet( + dataModelMigrations)) { + if (dataModelMigration.migrate(session)) { + restartAndClearCaches = true; + } + } + } catch (ArgeoException e) { + throw e; + } catch (Exception e) { + throw new ArgeoException("Cannot migrate", e); + } finally { + JcrUtils.logoutQuietly(session); + } + + // restart repository + if (restartAndClearCaches) { + Repository repository = getRepository(); + if (repository instanceof RepositoryImpl) { + JackrabbitDataModelMigration + .clearRepositoryCaches(((RepositoryImpl) repository) + .getConfig()); + } + ((JackrabbitRepository) repository).shutdown(); + createJackrabbitRepository(); + } + + // set data model version + try { + session = login(); + } catch (RepositoryException e) { + throw new ArgeoException("Cannot login to migrated repository", e); + } + + for (JackrabbitDataModelMigration dataModelMigration : new TreeSet( + dataModelMigrations)) { + try { + if (session.itemExists(dataModelMigration + .getDataModelNodePath())) { + Node dataModelNode = session.getNode(dataModelMigration + .getDataModelNodePath()); + dataModelNode.setProperty( + ArgeoNames.ARGEO_DATA_MODEL_VERSION, + dataModelMigration.getTargetVersion()); + session.save(); + } + } catch (Exception e) { + log.error("Cannot set model version", e); + } + } + JcrUtils.logoutQuietly(session); + + } + + /** Shutdown the repository */ + public void destroy() throws Exception { + Repository repository = getRepository(); + if (repository != null && repository instanceof RepositoryImpl) { + long begin = System.currentTimeMillis(); + ((RepositoryImpl) repository).shutdown(); + if (inMemory) + if (getHomeDirectory().exists()) { + FileUtils.deleteDirectory(getHomeDirectory()); + if (log.isDebugEnabled()) + log.debug("Deleted Jackrabbit home directory " + + getHomeDirectory()); + } + double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; + log.info("Destroyed Jackrabbit repository in " + duration + + " s, home: " + getHomeDirectory()); + } + repository = null; + } + + public void dispose() { + throw new IllegalArgumentException( + "Call destroy() method instead of dispose()"); + } + + /* + * UTILITIES + */ + /** + * Reads the configuration which will initialize a {@link RepositoryConfig}. + */ + protected InputStream readConfiguration() { + try { + return configuration != null ? configuration.getInputStream() + : null; + } catch (IOException e) { + throw new ArgeoException("Cannot read Jackrabbit configuration " + + configuration, e); + } + } + + /** + * Reads the variables which will initialize a {@link Properties}. Returns + * null by default, to be overridden. + * + * @return a new stream or null if no variables available + */ + protected InputStream readVariables() { + try { + return variables != null ? variables.getInputStream() : null; + } catch (IOException e) { + throw new ArgeoException("Cannot read Jackrabbit variables " + + variables, e); + } + } + + /** + * Resolves ${} placeholders in the provided string. Based on system + * properties if no map is provided. + */ + protected String resolvePlaceholders(String string, + Map variables) { + return SystemPropertyUtils.resolvePlaceholders(string); + } + + /** Generates the properties to use in the configuration. */ + protected Properties getConfigurationProperties() { + if (configurationProperties != null) + return configurationProperties; + + InputStream propsIn = null; + Properties vars; + try { + vars = new Properties(); + propsIn = readVariables(); + if (propsIn != null) { + vars.load(propsIn); + } + // resolve system properties + for (Object key : vars.keySet()) { + // TODO: implement a smarter mechanism to resolve nested ${} + String newValue = resolvePlaceholders( + vars.getProperty(key.toString()), null); + vars.put(key, newValue); + } + // override with system properties + vars.putAll(System.getProperties()); + + if (log.isTraceEnabled()) { + log.trace("Jackrabbit config variables:"); + for (Object key : new TreeSet(vars.keySet())) + log.trace(key + "=" + vars.getProperty(key.toString())); + } + + } catch (IOException e) { + throw new ArgeoException("Cannot read configuration properties", e); + } finally { + IOUtils.closeQuietly(propsIn); + } + return vars; + } + + /* + * FIELDS ACCESS + */ + + public void setHomeDirectory(File homeDirectory) { + this.homeDirectory = homeDirectory; + } + + public void setInMemory(Boolean inMemory) { + this.inMemory = inMemory; + } + + public void setRepository(Repository repository) { + throw new ArgeoException("Cannot be used to wrap another repository"); + } + + public void setDataModelMigrations( + Set dataModelMigrations) { + this.dataModelMigrations = dataModelMigrations; + } + + public void setVariables(Resource variables) { + this.variables = variables; + } + + public void setConfiguration(Resource configuration) { + this.configuration = configuration; + } + + public void setConfigurationProperties(Properties configurationProperties) { + this.configurationProperties = configurationProperties; + } + + public void setConfigurationXml(InputSource configurationXml) { + this.configurationXml = configurationXml; + } + +} diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java new file mode 100644 index 000000000..401b34df6 --- /dev/null +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitDataModelMigration.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.jackrabbit; + +import java.io.InputStreamReader; +import java.io.Reader; + +import javax.jcr.Node; +import javax.jcr.Session; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.commons.cnd.CndImporter; +import org.apache.jackrabbit.core.config.RepositoryConfig; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.JcrCallback; +import org.argeo.jcr.JcrUtils; +import org.springframework.core.io.Resource; + +/** Migrate the data in a Jackrabbit repository. */ +public class JackrabbitDataModelMigration implements + Comparable { + private final static Log log = LogFactory + .getLog(JackrabbitDataModelMigration.class); + + private String dataModelNodePath; + private String targetVersion; + private Resource migrationCnd; + private JcrCallback dataModification; + + /** + * Expects an already started repository with the old data model to migrate. + * Expects to be run with admin rights (Repository.login() will be used). + * + * @return true if a migration was performed and the repository needs to be + * restarted and its caches cleared. + */ + public Boolean migrate(Session session) { + long begin = System.currentTimeMillis(); + Reader reader = null; + try { + // check if already migrated + if (!session.itemExists(dataModelNodePath)) { + log.warn("Node " + dataModelNodePath + + " does not exist: nothing to migrate."); + return false; + } + Node dataModelNode = session.getNode(dataModelNodePath); + if (dataModelNode.hasProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION)) { + String currentVersion = dataModelNode.getProperty( + ArgeoNames.ARGEO_DATA_MODEL_VERSION).getString(); + if (compareVersions(currentVersion, targetVersion) >= 0) { + log.info("Data model at version " + currentVersion + + ", no need to migrate."); + return false; + } + } + + // apply transitional CND + if (migrationCnd != null) { + reader = new InputStreamReader(migrationCnd.getInputStream()); + CndImporter.registerNodeTypes(reader, session, true); + session.save(); + log.info("Registered migration node types from " + migrationCnd); + } + + // modify data + dataModification.execute(session); + + // apply changes + session.save(); + + long duration = System.currentTimeMillis() - begin; + log.info("Migration of data model " + dataModelNodePath + " to " + + targetVersion + " performed in " + duration + "ms"); + return true; + } catch (Exception e) { + JcrUtils.discardQuietly(session); + throw new ArgeoException("Migration of data model " + + dataModelNodePath + " to " + targetVersion + " failed.", + e); + } finally { + JcrUtils.logoutQuietly(session); + IOUtils.closeQuietly(reader); + } + } + + protected static int compareVersions(String version1, String version2) { + // TODO do a proper version analysis and comparison + return version1.compareTo(version2); + } + + /** To be called on a stopped repository. */ + public static void clearRepositoryCaches(RepositoryConfig repositoryConfig) { + try { + String customeNodeTypesPath = "/nodetypes/custom_nodetypes.xml"; + repositoryConfig.getFileSystem().deleteFile(customeNodeTypesPath); + if (log.isDebugEnabled()) + log.debug("Cleared " + customeNodeTypesPath); + } catch (Exception e) { + throw new ArgeoException("Cannot clear caches", e); + } + + // File customNodeTypes = new File(home.getPath() + // + "/repository/nodetypes/custom_nodetypes.xml"); + // if (customNodeTypes.exists()) { + // customNodeTypes.delete(); + // if (log.isDebugEnabled()) + // log.debug("Cleared " + customNodeTypes); + // } else { + // log.warn("File " + customNodeTypes + " not found."); + // } + } + + /* + * FOR USE IN (SORTED) SETS + */ + + public int compareTo(JackrabbitDataModelMigration dataModelMigration) { + // TODO make ordering smarter + if (dataModelNodePath.equals(dataModelMigration.dataModelNodePath)) + return compareVersions(targetVersion, + dataModelMigration.targetVersion); + else + return dataModelNodePath + .compareTo(dataModelMigration.dataModelNodePath); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof JackrabbitDataModelMigration)) + return false; + JackrabbitDataModelMigration dataModelMigration = (JackrabbitDataModelMigration) obj; + return dataModelNodePath.equals(dataModelMigration.dataModelNodePath) + && targetVersion.equals(dataModelMigration.targetVersion); + } + + @Override + public int hashCode() { + return targetVersion.hashCode(); + } + + public void setDataModelNodePath(String dataModelNodePath) { + this.dataModelNodePath = dataModelNodePath; + } + + public void setTargetVersion(String targetVersion) { + this.targetVersion = targetVersion; + } + + public void setMigrationCnd(Resource migrationCnd) { + this.migrationCnd = migrationCnd; + } + + public void setDataModification(JcrCallback dataModification) { + this.dataModification = dataModification; + } + + public String getDataModelNodePath() { + return dataModelNodePath; + } + + public String getTargetVersion() { + return targetVersion; + } + +} diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java new file mode 100644 index 000000000..d64bb5e68 --- /dev/null +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitRepositoryFactory.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.jackrabbit; + +import java.io.File; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.RepositoryFactory; +import javax.jcr.Session; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.commons.JcrUtils; +import org.apache.jackrabbit.core.RepositoryImpl; +import org.apache.jackrabbit.core.config.RepositoryConfig; +import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; +import org.apache.jackrabbit.jcr2dav.Jcr2davRepositoryFactory; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.jcr.DefaultRepositoryFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.xml.sax.InputSource; + +/** + * Repository factory which can create new repositories and access remote + * Jackrabbit repositories + */ +public class JackrabbitRepositoryFactory extends DefaultRepositoryFactory + implements RepositoryFactory, ArgeoJcrConstants { + + private final static Log log = LogFactory + .getLog(JackrabbitRepositoryFactory.class); + + private Resource fileRepositoryConfiguration = new ClassPathResource( + "/org/argeo/jackrabbit/repository-h2.xml"); + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public Repository getRepository(Map parameters) throws RepositoryException { + // check if can be found by alias + Repository repository = super.getRepository(parameters); + if (repository != null) + return repository; + + // check if remote + String uri = null; + if (parameters.containsKey(JCR_REPOSITORY_URI)) + uri = parameters.get(JCR_REPOSITORY_URI).toString(); + else if (parameters.containsKey(JcrUtils.REPOSITORY_URI)) + uri = parameters.get(JcrUtils.REPOSITORY_URI).toString(); + + if (uri != null) { + if (uri.startsWith("http"))// http, https + repository = createRemoteRepository(uri); + else if (uri.startsWith("file"))// http, https + repository = createFileRepository(uri, parameters); + else if (uri.startsWith("vm")) { + log.warn("URI " + + uri + + " should have been managed by generic JCR repository factory"); + repository = getRepositoryByAlias(getAliasFromURI(uri)); + } + } + + // publish under alias + if (parameters.containsKey(JCR_REPOSITORY_ALIAS)) { + Properties properties = new Properties(); + properties.putAll(parameters); + String alias = parameters.get(JCR_REPOSITORY_ALIAS).toString(); + publish(alias, repository, properties); + log.info("Registered JCR repository under alias '" + alias + + "' with properties " + properties); + } + + return repository; + } + + protected Repository createRemoteRepository(String uri) + throws RepositoryException { + Map params = new HashMap(); + params.put(JcrUtils.REPOSITORY_URI, uri); + Repository repository = new Jcr2davRepositoryFactory() + .getRepository(params); + if (repository == null) + throw new ArgeoException("Remote Davex repository " + uri + + " not found"); + log.info("Initialized remote Jackrabbit repository from uri " + uri); + return repository; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected Repository createFileRepository(final String uri, Map parameters) + throws RepositoryException { + InputStream configurationIn = null; + try { + Properties vars = new Properties(); + vars.putAll(parameters); + String dirPath = uri.substring("file:".length()); + File homeDir = new File(dirPath); + if (homeDir.exists() && !homeDir.isDirectory()) + throw new ArgeoException("Repository home " + dirPath + + " is not a directory"); + if (!homeDir.exists()) + homeDir.mkdirs(); + configurationIn = fileRepositoryConfiguration.getInputStream(); + vars.put(RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, + homeDir.getCanonicalPath()); + RepositoryConfig repositoryConfig = RepositoryConfig.create( + new InputSource(configurationIn), vars); + + // TransientRepository repository = new + // TransientRepository(repositoryConfig); + final RepositoryImpl repository = RepositoryImpl + .create(repositoryConfig); + Session session = repository.login(); + // FIXME make it generic + org.argeo.jcr.JcrUtils.addPrivilege(session, "/", "ROLE_ADMIN", + "jcr:all"); + org.argeo.jcr.JcrUtils.logoutQuietly(session); + Runtime.getRuntime().addShutdownHook( + new Thread("Clean JCR repository " + uri) { + public void run() { + repository.shutdown(); + log.info("Destroyed repository " + uri); + } + }); + log.info("Initialized file Jackrabbit repository from uri " + uri); + return repository; + } catch (Exception e) { + throw new ArgeoException("Cannot create repository " + uri, e); + } finally { + IOUtils.closeQuietly(configurationIn); + } + } + + /** + * Called after the repository has been initialised. Does nothing by + * default. + */ + @SuppressWarnings("rawtypes") + protected void postInitialization(Repository repository, Map parameters) { + + } + + public void setFileRepositoryConfiguration( + Resource fileRepositoryConfiguration) { + this.fileRepositoryConfiguration = fileRepositoryConfiguration; + } + +} diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitWrapper.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitWrapper.java new file mode 100644 index 000000000..53a9ff1e2 --- /dev/null +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitWrapper.java @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.jackrabbit; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.jcr.Credentials; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Repository; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.commons.NamespaceHelper; +import org.apache.jackrabbit.commons.cnd.CndImporter; +import org.argeo.ArgeoException; +import org.argeo.jcr.ArgeoJcrConstants; +import org.argeo.jcr.ArgeoNames; +import org.argeo.jcr.ArgeoTypes; +import org.argeo.jcr.JcrRepositoryWrapper; +import org.argeo.jcr.JcrUtils; +import org.argeo.util.security.DigestUtils; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.service.packageadmin.ExportedPackage; +import org.osgi.service.packageadmin.PackageAdmin; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; + +/** + * Wrapper around a Jackrabbit repository which allows to simplify configuration + * and intercept some actions. It exposes itself as a {@link Repository}. + */ +public class JackrabbitWrapper extends JcrRepositoryWrapper implements + ResourceLoaderAware { + private final static Log log = LogFactory.getLog(JackrabbitWrapper.class); + private final static String DIGEST_ALGORITHM = "MD5"; + + // local + private ResourceLoader resourceLoader; + + // data model + /** Node type definitions in CND format */ + private List cndFiles = new ArrayList(); + /** + * Always import CNDs. Useful during development of new data models. In + * production, explicit migration processes should be used. + */ + private Boolean forceCndImport = true; + + /** Namespaces to register: key is prefix, value namespace */ + private Map namespaces = new HashMap(); + + private BundleContext bundleContext; + + /** + * Explicitly set admin credentials used in initialization. Useful for + * testing, in real applications authentication is rather dealt with + * externally + */ + private Credentials adminCredentials = null; + + /** + * Empty constructor, {@link #init()} should be called after properties have + * been set + */ + public JackrabbitWrapper() { + } + + @Override + public void init() { + prepareDataModel(); + } + + /* + * DATA MODEL + */ + + /** + * Import declared node type definitions and register namespaces. Tries to + * update the node definitions if they have changed. In case of failures an + * error will be logged but no exception will be thrown. + */ + protected void prepareDataModel() { + if ((cndFiles == null || cndFiles.size() == 0) + && (namespaces == null || namespaces.size() == 0)) + return; + + Session session = null; + try { + session = login(adminCredentials); + // register namespaces + if (namespaces.size() > 0) { + NamespaceHelper namespaceHelper = new NamespaceHelper(session); + namespaceHelper.registerNamespaces(namespaces); + } + + // load CND files from classpath or as URL + for (String resUrl : cndFiles) { + processCndFile(session, resUrl); + } + } catch (Exception e) { + JcrUtils.discardQuietly(session); + throw new ArgeoException("Cannot import node type definitions " + + cndFiles, e); + } finally { + JcrUtils.logoutQuietly(session); + } + + } + + protected void processCndFile(Session session, String resUrl) { + Reader reader = null; + try { + // check existing data model nodes + new NamespaceHelper(session).registerNamespace(ArgeoNames.ARGEO, + ArgeoNames.ARGEO_NAMESPACE); + if (!session.itemExists(ArgeoJcrConstants.DATA_MODELS_BASE_PATH)) + JcrUtils.mkdirs(session, + ArgeoJcrConstants.DATA_MODELS_BASE_PATH); + Node dataModels = session + .getNode(ArgeoJcrConstants.DATA_MODELS_BASE_PATH); + NodeIterator it = dataModels.getNodes(); + Node dataModel = null; + while (it.hasNext()) { + Node node = it.nextNode(); + if (node.getProperty(ArgeoNames.ARGEO_URI).getString() + .equals(resUrl)) { + dataModel = node; + break; + } + } + + byte[] cndContent = readCndContent(resUrl); + String newDigest = DigestUtils.digest(DIGEST_ALGORITHM, cndContent); + Bundle bundle = findDataModelBundle(resUrl); + + String currentVersion = null; + if (dataModel != null) { + currentVersion = dataModel.getProperty( + ArgeoNames.ARGEO_DATA_MODEL_VERSION).getString(); + if (dataModel.hasNode(Node.JCR_CONTENT)) { + String oldDigest = JcrUtils.checksumFile(dataModel, + DIGEST_ALGORITHM); + if (oldDigest.equals(newDigest)) { + if (log.isDebugEnabled()) + log.debug("Data model " + resUrl + + " hasn't changed, keeping version " + + currentVersion); + return; + } + } + } + + if (dataModel != null && !forceCndImport) { + log.info("Data model " + + resUrl + + " has changed since version " + + currentVersion + + (bundle != null ? ": version " + bundle.getVersion() + + ", bundle " + bundle.getSymbolicName() : "")); + return; + } + + reader = new InputStreamReader(new ByteArrayInputStream(cndContent)); + // actually imports the CND + try { + CndImporter.registerNodeTypes(reader, session, true); + } catch (Exception e) { + log.error("Cannot import data model " + resUrl, e); + return; + } + + if (dataModel != null && !dataModel.isNodeType(NodeType.NT_FILE)) { + dataModel.remove(); + dataModel = null; + } + + // FIXME: what if argeo.cnd would not be the first called on + // a new repo? argeo:dataModel would not be found + String fileName = FilenameUtils.getName(resUrl); + if (dataModel == null) { + dataModel = dataModels.addNode(fileName, NodeType.NT_FILE); + dataModel.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE); + dataModel.addMixin(ArgeoTypes.ARGEO_DATA_MODEL); + dataModel.setProperty(ArgeoNames.ARGEO_URI, resUrl); + } else { + session.getWorkspace().getVersionManager() + .checkout(dataModel.getPath()); + } + if (bundle != null) + dataModel.setProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION, + bundle.getVersion().toString()); + else + dataModel.setProperty(ArgeoNames.ARGEO_DATA_MODEL_VERSION, + "0.0.0"); + JcrUtils.copyBytesAsFile(dataModel.getParent(), fileName, + cndContent); + JcrUtils.updateLastModified(dataModel); + session.save(); + session.getWorkspace().getVersionManager() + .checkin(dataModel.getPath()); + + if (currentVersion == null) + log.info("Data model " + + resUrl + + (bundle != null ? ", version " + bundle.getVersion() + + ", bundle " + bundle.getSymbolicName() : "")); + else + log.info("Data model " + + resUrl + + " updated from version " + + currentVersion + + (bundle != null ? ", version " + bundle.getVersion() + + ", bundle " + bundle.getSymbolicName() : "")); + } catch (Exception e) { + throw new ArgeoException("Cannot process data model " + resUrl, e); + } finally { + IOUtils.closeQuietly(reader); + } + } + + protected byte[] readCndContent(String resUrl) { + InputStream in = null; + try { + boolean classpath; + // normalize URL + if (bundleContext != null && resUrl.startsWith("classpath:")) { + resUrl = resUrl.substring("classpath:".length()); + classpath = true; + } else if (resUrl.indexOf(':') < 0) { + if (!resUrl.startsWith("/")) { + resUrl = "/" + resUrl; + log.warn("Classpath should start with '/'"); + } + classpath = true; + } else { + classpath = false; + } + + URL url = null; + if (classpath) { + if (bundleContext != null) { + Bundle currentBundle = bundleContext.getBundle(); + url = currentBundle.getResource(resUrl); + } else { + resUrl = "classpath:" + resUrl; + url = null; + } + } else if (!resUrl.startsWith("classpath:")) { + url = new URL(resUrl); + } + + if (url != null) { + in = url.openStream(); + } else if (resourceLoader != null) { + Resource res = resourceLoader.getResource(resUrl); + in = res.getInputStream(); + url = res.getURL(); + } else { + throw new ArgeoException("No " + resUrl + " in the classpath," + + " make sure the containing" + " package is visible."); + } + + return IOUtils.toByteArray(in); + } catch (Exception e) { + throw new ArgeoException("Cannot read CND from " + resUrl, e); + } finally { + IOUtils.closeQuietly(in); + } + } + + /* + * REPOSITORY INTERCEPTOR + */ + + /* + * UTILITIES + */ + /** Find which OSGi bundle provided the data model resource */ + protected Bundle findDataModelBundle(String resUrl) { + if (bundleContext == null) + return null; + + if (resUrl.startsWith("/")) + resUrl = resUrl.substring(1); + String pkg = resUrl.substring(0, resUrl.lastIndexOf('/')).replace('/', + '.'); + ServiceReference paSr = bundleContext + .getServiceReference(PackageAdmin.class.getName()); + PackageAdmin packageAdmin = (PackageAdmin) bundleContext + .getService(paSr); + + // find exported package + ExportedPackage exportedPackage = null; + ExportedPackage[] exportedPackages = packageAdmin + .getExportedPackages(pkg); + if (exportedPackages == null) + throw new ArgeoException("No exported package found for " + pkg); + for (ExportedPackage ep : exportedPackages) { + for (Bundle b : ep.getImportingBundles()) { + if (b.getBundleId() == bundleContext.getBundle().getBundleId()) { + exportedPackage = ep; + break; + } + } + } + + Bundle exportingBundle = null; + if (exportedPackage != null) { + exportingBundle = exportedPackage.getExportingBundle(); + } else { + // assume this is in the same bundle + exportingBundle = bundleContext.getBundle(); + // throw new ArgeoException("No OSGi exporting package found for " + // + resUrl); + } + return exportingBundle; + } + + /* + * FIELDS ACCESS + */ + public void setNamespaces(Map namespaces) { + this.namespaces = namespaces; + } + + public void setCndFiles(List cndFiles) { + this.cndFiles = cndFiles; + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + protected BundleContext getBundleContext() { + return bundleContext; + } + + public void setForceCndImport(Boolean forceCndUpdate) { + this.forceCndImport = forceCndUpdate; + } + + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + public void setAdminCredentials(Credentials adminCredentials) { + this.adminCredentials = adminCredentials; + } + +} diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java new file mode 100644 index 000000000..b28699e60 --- /dev/null +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/OsgiJackrabbitRepositoryFactory.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.jackrabbit; + +import java.util.Hashtable; +import java.util.Properties; + +import javax.jcr.Repository; + +import org.osgi.framework.BundleContext; + +/** + * OSGi-aware Jackrabbit repository factory which can retrieve/publish + * {@link Repository} as OSGi services. + */ +public class OsgiJackrabbitRepositoryFactory extends + JackrabbitRepositoryFactory { + private BundleContext bundleContext; + + protected void publish(String alias, Repository repository, + Properties properties) { + if (bundleContext != null) { + // do not modify reference + Hashtable props = new Hashtable(); + props.putAll(props); + props.put(JCR_REPOSITORY_ALIAS, alias); + bundleContext.registerService(Repository.class.getName(), + repository, props); + } + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + +} diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-fs.xml b/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-fs.xml new file mode 100644 index 000000000..609fc8b33 --- /dev/null +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-fs.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-h2.xml b/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-h2.xml new file mode 100644 index 000000000..b6a92528a --- /dev/null +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-h2.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-memory.xml b/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-memory.xml new file mode 100644 index 000000000..e552c33a7 --- /dev/null +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/repository-memory.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/servlet/OpenInViewSessionProvider.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/servlet/OpenInViewSessionProvider.java new file mode 100644 index 000000000..519a21840 --- /dev/null +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/servlet/OpenInViewSessionProvider.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.jackrabbit.servlet; + +import java.io.Serializable; + +import javax.jcr.LoginException; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.server.SessionProvider; +import org.argeo.jcr.JcrUtils; + +/** + * Implements an open session in view patter: a new JCR session is created for + * each request + */ +public class OpenInViewSessionProvider implements SessionProvider, Serializable { + private static final long serialVersionUID = 2270957712453841368L; + + private final static Log log = LogFactory + .getLog(OpenInViewSessionProvider.class); + + public Session getSession(HttpServletRequest request, Repository rep, + String workspace) throws LoginException, ServletException, + RepositoryException { + return login(request, rep, workspace); + } + + protected Session login(HttpServletRequest request, Repository repository, + String workspace) throws RepositoryException { + if (log.isTraceEnabled()) + log.trace("Login to workspace " + + (workspace == null ? "" : workspace) + + " in web session " + request.getSession().getId()); + return repository.login(workspace); + } + + public void releaseSession(Session session) { + JcrUtils.logoutQuietly(session); + if (log.isTraceEnabled()) + log.trace("Logged out remote JCR session " + session); + } + + public void init() { + } + + public void destroy() { + } + +} diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/servlet/RemotingServlet.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/servlet/RemotingServlet.java new file mode 100644 index 000000000..01bbb355d --- /dev/null +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/servlet/RemotingServlet.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.jackrabbit.servlet; + +import javax.jcr.Repository; + +import org.apache.jackrabbit.server.SessionProvider; +import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet; + +/** Provides remote access to a JCR repository */ +public class RemotingServlet extends JcrRemotingServlet { + public final static String INIT_PARAM_RESOURCE_PATH_PREFIX = JcrRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX; + public final static String INIT_PARAM_HOME = JcrRemotingServlet.INIT_PARAM_HOME; + public final static String INIT_PARAM_TMP_DIRECTORY = JcrRemotingServlet.INIT_PARAM_TMP_DIRECTORY; + + private static final long serialVersionUID = 3131835511468341309L; + + private final Repository repository; + private final SessionProvider sessionProvider; + + public RemotingServlet(Repository repository, + SessionProvider sessionProvider) { + this.repository = repository; + this.sessionProvider = sessionProvider; + } + + @Override + protected Repository getRepository() { + return repository; + } + + @Override + protected SessionProvider getSessionProvider() { + return sessionProvider; + } + +} diff --git a/org.argeo.server.jcr/src/org/argeo/jackrabbit/servlet/WebdavServlet.java b/org.argeo.server.jcr/src/org/argeo/jackrabbit/servlet/WebdavServlet.java new file mode 100644 index 000000000..c2346f00e --- /dev/null +++ b/org.argeo.server.jcr/src/org/argeo/jackrabbit/servlet/WebdavServlet.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.jackrabbit.servlet; + +import java.io.IOException; + +import javax.jcr.Repository; +import javax.servlet.ServletException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.server.SessionProvider; +import org.apache.jackrabbit.webdav.DavException; +import org.apache.jackrabbit.webdav.DavResource; +import org.apache.jackrabbit.webdav.WebdavRequest; +import org.apache.jackrabbit.webdav.WebdavResponse; +import org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet; + +/** WebDav servlet whose repository is injected */ +public class WebdavServlet extends SimpleWebdavServlet { + public final static String INIT_PARAM_RESOURCE_CONFIG = SimpleWebdavServlet.INIT_PARAM_RESOURCE_CONFIG; + public final static String INIT_PARAM_RESOURCE_PATH_PREFIX = SimpleWebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX; + + private static final long serialVersionUID = -369787931175177080L; + + private final static Log log = LogFactory.getLog(WebdavServlet.class); + + private final Repository repository; + + public WebdavServlet(Repository repository, SessionProvider sessionProvider) { + this.repository = repository; + setSessionProvider(sessionProvider); + } + + public Repository getRepository() { + return repository; + } + + @Override + protected boolean execute(WebdavRequest request, WebdavResponse response, + int method, DavResource resource) throws ServletException, + IOException, DavException { + if (log.isTraceEnabled()) + log.trace(request.getMethod() + "\t" + request.getPathInfo()); + boolean res = super.execute(request, response, method, resource); + return res; + } + +} diff --git a/org.argeo.util/pom.xml b/org.argeo.util/pom.xml index a1bbc8a71..0cb1341e1 100644 --- a/org.argeo.util/pom.xml +++ b/org.argeo.util/pom.xml @@ -8,21 +8,5 @@ .. org.argeo.util - Commons Util (no third party dependencies) - - - - - - - - - - - - - - - - + Commons Utilities \ No newline at end of file diff --git a/pom.xml b/pom.xml index e10581b25..8959e0fbb 100644 --- a/pom.xml +++ b/pom.xml @@ -25,30 +25,18 @@ org.argeo.security.core org.argeo.security.jackrabbit - org.argeo.security.ldap - - - - - - - org.argeo.server.core - - org.argeo.server.jackrabbit org.argeo.eclipse.ui org.argeo.eclipse.ui.rap - - + org.argeo.cms org.argeo.eclipse.ui.workbench org.argeo.eclipse.ui.workbench.rap - org.argeo.security.ui org.argeo.security.ui.admin org.argeo.security.ui.rap - + dep dist