You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/02/23 11:06:25 UTC
[5/5] incubator-taverna-osgi git commit: Revert "temporarily empty
repository"
Revert "temporarily empty repository"
This reverts commit 2f5a0e941bdf0afee66e9a5f1c3d188d40803e83.
Project: http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/commit/c9bb093a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/tree/c9bb093a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/diff/c9bb093a
Branch: refs/heads/master
Commit: c9bb093ac3ea4c32472265a3303b32b40203b58f
Parents: 2f5a0e9
Author: Stian Soiland-Reyes <st...@apache.org>
Authored: Mon Feb 23 10:05:41 2015 +0000
Committer: Stian Soiland-Reyes <st...@apache.org>
Committed: Mon Feb 23 10:05:41 2015 +0000
----------------------------------------------------------------------
.gitignore | 24 +
.travis.yml | 1 +
LICENSE | 176 +++++++
README.md | 8 +
osgi-launcher/pom.xml | 19 +
.../java/uk/org/taverna/osgi/OsgiLauncher.java | 434 +++++++++++++++++
pom.xml | 46 ++
taverna-app-configuration-api/.project | 24 +
taverna-app-configuration-api/pom.xml | 19 +
.../app/ApplicationConfiguration.java | 62 +++
taverna-app-configuration-impl/.project | 24 +
taverna-app-configuration-impl/pom.xml | 43 ++
.../app/impl/ApplicationConfigurationImpl.java | 293 ++++++++++++
.../app/impl/ApplicationUserHome.java | 224 +++++++++
.../app/impl/Log4JConfiguration.java | 161 +++++++
.../spring/configuration-context-osgi.xml | 11 +
.../META-INF/spring/configuration-context.xml | 14 +
taverna-configuration-api/.project | 24 +
taverna-configuration-api/pom.xml | 30 ++
.../configuration/AbstractConfigurable.java | 184 ++++++++
.../org/taverna/configuration/Configurable.java | 118 +++++
.../configuration/ConfigurationManager.java | 51 ++
.../configuration/ConfigurationUIFactory.java | 29 ++
.../uk/org/taverna/configuration/package.html | 3 +
.../proxy/HttpProxyConfiguration.java | 79 ++++
.../configuration/AbstractConfigurableTest.java | 244 ++++++++++
.../configuration/DummyConfigurable.java | 65 +++
taverna-configuration-impl/.project | 24 +
taverna-configuration-impl/pom.xml | 79 ++++
.../impl/ConfigurationManagerImpl.java | 153 ++++++
.../proxy/impl/HttpProxyConfigurationImpl.java | 166 +++++++
.../spring/configuration-context-osgi.xml | 14 +
.../META-INF/spring/configuration-context.xml | 16 +
.../impl/ConfigurationManagerImplTest.java | 182 ++++++++
.../configuration/impl/DummyUIFactory1.java | 126 +++++
.../configuration/impl/DummyUIFactory2.java | 126 +++++
taverna-download-api/pom.xml | 12 +
.../commons/download/DownloadException.java | 45 ++
.../commons/download/DownloadManager.java | 116 +++++
taverna-download-impl/pom.xml | 48 ++
.../download/impl/DownloadManagerImpl.java | 120 +++++
.../META-INF/spring/download-context-osgi.xml | 11 +
.../META-INF/spring/download-context.xml | 9 +
taverna-maven-plugin/pom.xml | 104 +++++
.../t2/maven/plugins/AbstractDeployMojo.java | 56 +++
.../t2/maven/plugins/AbstractWagonMojo.java | 60 +++
.../t2/maven/plugins/BundleArtifact.java | 66 +++
.../t2/maven/plugins/MavenOsgiUtils.java | 415 +++++++++++++++++
.../sf/taverna/t2/maven/plugins/Package.java | 46 ++
.../t2/maven/plugins/PackageVersion.java | 77 +++
.../plugins/TavernaPluginDeployFileMojo.java | 235 ++++++++++
.../maven/plugins/TavernaPluginDeployMojo.java | 220 +++++++++
.../plugins/TavernaPluginGenerateMojo.java | 142 ++++++
.../TavernaPluginPrepareBundlesMojo.java | 84 ++++
.../maven/plugins/TavernaProfileDeployMojo.java | 275 +++++++++++
.../plugins/TavernaProfileGenerateMojo.java | 221 +++++++++
.../net/sf/taverna/t2/maven/plugins/Utils.java | 171 +++++++
.../resources/META-INF/plexus/components.xml | 30 ++
.../src/main/resources/java7-packages | 209 +++++++++
.../plugins/TavernaPluginGenerateMojoTest.java | 80 ++++
.../src/test/resources/unit/plugin-config.xml | 19 +
taverna-osgi-schemas/pom.xml | 27 ++
.../src/main/resources/ApplicationPlugin.xsd | 67 +++
.../src/main/resources/ApplicationProfile.xsd | 75 +++
.../src/main/resources/ApplicationVersions.xsd | 44 ++
taverna-plugin-api/pom.xml | 29 ++
.../uk/org/taverna/commons/plugin/Plugin.java | 88 ++++
.../taverna/commons/plugin/PluginException.java | 45 ++
.../taverna/commons/plugin/PluginManager.java | 105 +++++
.../org/taverna/commons/plugin/PluginSite.java | 65 +++
.../commons/plugin/PluginSiteManager.java | 86 ++++
taverna-plugin-impl/pom.xml | 81 ++++
.../plugin/impl/PluginDirectoryWatcher.java | 106 +++++
.../taverna/commons/plugin/impl/PluginImpl.java | 183 ++++++++
.../commons/plugin/impl/PluginManagerImpl.java | 466 +++++++++++++++++++
.../commons/plugin/impl/PluginSiteImpl.java | 76 +++
.../plugin/impl/PluginSiteManagerImpl.java | 190 ++++++++
.../commons/plugin/impl/PluginSites.java | 50 ++
.../META-INF/spring/plugin-context-osgi.xml | 17 +
.../META-INF/spring/plugin-context.xml | 31 ++
.../commons/plugin/impl/PluginSiteImplTest.java | 72 +++
.../plugin/impl/PluginSiteManagerImplTest.java | 142 ++++++
taverna-update-api/pom.xml | 12 +
.../taverna/commons/update/UpdateException.java | 47 ++
.../taverna/commons/update/UpdateManager.java | 34 ++
taverna-update-impl/pom.xml | 63 +++
.../commons/update/impl/UpdateManagerImpl.java | 270 +++++++++++
.../META-INF/spring/update-context-osgi.xml | 16 +
.../META-INF/spring/update-context.xml | 21 +
xml-parser-service/.project | 24 +
xml-parser-service/pom.xml | 40 ++
.../javax.xml.parsers.DocumentBuilderFactory | 1 +
.../services/javax.xml.parsers.SAXParserFactory | 1 +
xml-transformer-service/.project | 24 +
xml-transformer-service/pom.xml | 45 ++
.../services/xml/XMLTransformerActivator.java | 147 ++++++
.../javax.xml.transform.TransformerFactory | 1 +
97 files changed, 8958 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ebe0e5b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+# ignore project files #
+.classpath
+.project
+.settings/
+catalog-v001.xml
+
+# ignore target files #
+target/
+bin/
+build/
+dist/
+apidoc/
+*.swp
+
+# ignore svn files if there
+.svn
+
+# ignore log files #
+*.log
+/logs/*
+*/logs/*
+
+
+
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..dff5f3a
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1 @@
+language: java
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..68c771a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,176 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..dd2958f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,8 @@
+# Apache Taverna OSGi plugin system
+
+[![Build Status](https://travis-ci.org/taverna-incubator/incubator-taverna-osgi.svg)](https://travis-ci.org/taverna-incubator/incubator-taverna-osgi)
+
+OSGi-based plugin system, including online updates. Written for Apache Taverna, probably
+usable for any OSGi-based command line/desktop product.
+
+
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/osgi-launcher/pom.xml
----------------------------------------------------------------------
diff --git a/osgi-launcher/pom.xml b/osgi-launcher/pom.xml
new file mode 100644
index 0000000..f2c6996
--- /dev/null
+++ b/osgi-launcher/pom.xml
@@ -0,0 +1,19 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.taverna.osgi</groupId>
+ <artifactId>taverna-osgi</artifactId>
+ <version>0.2.0-incubating-SNAPSHOT</version>
+ </parent>
+ <artifactId>osgi-launcher</artifactId>
+ <name>OSGi Framework Launcher</name>
+ <description>Launches an OSGi framework and handles loading and starting of OSGi bundles and Spring DM managed services</description>
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>${osgi.core.version}</version>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/osgi-launcher/src/main/java/uk/org/taverna/osgi/OsgiLauncher.java
----------------------------------------------------------------------
diff --git a/osgi-launcher/src/main/java/uk/org/taverna/osgi/OsgiLauncher.java b/osgi-launcher/src/main/java/uk/org/taverna/osgi/OsgiLauncher.java
new file mode 100644
index 0000000..cfd006b
--- /dev/null
+++ b/osgi-launcher/src/main/java/uk/org/taverna/osgi/OsgiLauncher.java
@@ -0,0 +1,434 @@
+/*******************************************************************************
+ * Copyright (C) 2012 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package uk.org.taverna.osgi;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.launch.FrameworkFactory;
+
+/**
+ * OSGi Framework launcher.
+ *
+ * Handles loading and starting of OSGi bundles and Spring DM managed services.
+ *
+ * An implementation of an OSGi Service Platform Release 4.1 (or higher) must be available on the
+ * classpath.
+ *
+ * @author David Withers
+ */
+public class OsgiLauncher {
+
+ /**
+ * Default boot delegation packages.
+ */
+ public static final String DEFAULT_BOOT_DELEGATION_PACKAGES = "sun.*,com.sun.*,java.*";
+
+ /**
+ * Default system packages.
+ */
+ public static final String DEFAULT_SYSTEM_PACKAGES = "com.sun.org.apache.xml.internal.utils";
+
+ /**
+ * Default time to wait for services to start up.
+ */
+ private static final long serviceLoadTimeoutSeconds = 30;
+
+ private static final Logger logger = Logger.getLogger(OsgiLauncher.class.getName());
+
+ private Framework framework;
+ private BundleContext context;
+
+ private Map<String, String> frameworkConfiguration = new HashMap<String, String>();
+ private List<URI> bundlesToInstall = new ArrayList<URI>();
+ private List<Bundle> installedBundles = new ArrayList<Bundle>();
+ private Set<String> startedSpringContexts = new HashSet<String>();
+ private Bundle springOsgiExtender;
+
+ private OsgiLauncher(File storageDirectory) {
+ setStorageDirectory(storageDirectory);
+ setCleanStorageDirectory(true);
+ setBootDelegationPackages(DEFAULT_BOOT_DELEGATION_PACKAGES);
+ setSystemPackages(DEFAULT_SYSTEM_PACKAGES);
+ }
+
+ /**
+ * Constructs an <code>OsgiLauncher</code> that loads bundles from a directory.
+ *
+ * Any file in the specified directory with a .jar extension will be loaded when the framework
+ * is started.
+ *
+ * @param storageDirectory
+ * persistent storage area used by the framework
+ * @param storageDirectory
+ * the directory containing bundles to load
+ */
+ public OsgiLauncher(File storageDirectory, File bundleDirectory) {
+ this(storageDirectory);
+ List<File> jars = Arrays.asList(bundleDirectory.listFiles(new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".jar");
+ }
+ }));
+ for (File jar : jars) {
+ bundlesToInstall.add(jar.toURI());
+ }
+ }
+
+ /**
+ * Constructs an <code>OsgiLauncher</code> that loads the specified bundles.
+ *
+ * @param storageDirectory
+ * persistent storage area used by the framework
+ * @param bundleURIs
+ * bundles to load
+ */
+ public OsgiLauncher(File storageDirectory, List<URI> bundleURIs) {
+ this(storageDirectory);
+ for (URI bundleURI : bundleURIs) {
+ bundlesToInstall.add(bundleURI);
+ }
+ }
+
+ /**
+ * Starts the OSGi framework, installs and starts the bundles.
+ *
+ * @throws BundleException
+ * if the framework could not be started
+ */
+ public void start() throws BundleException {
+ logger.info("Loading the OSGi Framework Factory");
+ FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator()
+ .next();
+
+ logger.info("Creating the OSGi Framework");
+ framework = frameworkFactory.newFramework(frameworkConfiguration);
+ logger.info("Starting the OSGi Framework");
+ framework.start();
+
+ context = framework.getBundleContext();
+ context.addServiceListener(new ServiceListener() {
+ public void serviceChanged(ServiceEvent event) {
+ ServiceReference serviceReference = event.getServiceReference();
+ if (event.getType() == ServiceEvent.REGISTERED) {
+ Object property = serviceReference
+ .getProperty("org.springframework.context.service.name");
+ if (property != null) {
+ addStartedSpringContext(property.toString());
+ }
+ }
+ logger.fine((event.getType() == ServiceEvent.REGISTERED ? "Registering : "
+ : "Unregistering : ") + serviceReference);
+ }
+ });
+
+ installedBundles = installBundles(bundlesToInstall);
+
+ List<Bundle> bundlesToStart = new ArrayList<Bundle>();
+ for (Bundle bundle : installedBundles) {
+ if ("org.springframework.osgi.extender".equals(bundle.getSymbolicName())) {
+ springOsgiExtender = bundle;
+ } else {
+ bundlesToStart.add(bundle);
+ }
+ }
+ startBundles(bundlesToStart);
+ }
+
+ /**
+ * Starts SpringDM managed services.
+ *
+ * @param waitForServices
+ * if true waits for services to start before returning
+ * @throws BundleException
+ * if the framework has not been started or a service could not be started
+ */
+ public void startServices(boolean waitForServices) throws BundleException {
+ if (framework == null || framework.getState() != Bundle.ACTIVE) {
+ throw new BundleException("Framework not started");
+ }
+ if (springOsgiExtender != null) {
+ logger.info("Starting Spring OSGi Extender");
+ springOsgiExtender.start();
+ if (waitForServices) {
+ logger.info("Waiting for spring contexts to be started");
+ for (Bundle bundle : installedBundles) {
+ if (bundle.getState() == Bundle.ACTIVE) {
+ if (hasSpringContext(bundle)) {
+ logger.fine("Waiting for " + bundle.getSymbolicName());
+ waitForSpringContext(context, bundle.getSymbolicName(), serviceLoadTimeoutSeconds);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Stops the OSGI framework.
+ *
+ * @throws BundleException
+ * if the framework has not been started
+ * @throws InterruptedException
+ * if the thread is interrupted while the framework is stopping
+ */
+ public void stop() throws BundleException, InterruptedException {
+ if (framework == null || framework.getState() != Bundle.ACTIVE) {
+ throw new BundleException("Framework not started");
+ }
+ framework.stop();
+ framework.waitForStop(0);
+ context = null;
+ }
+
+ /**
+ * Installs the bundles specified by the URIs into the framework.
+ *
+ * @param bundlesURIs
+ * the URIs of the bundles to install
+ * @return the installed bundles
+ * @throws BundleException
+ * if a bundle could not be installed
+ */
+ public List<Bundle> installBundles(List<URI> bundlesURIs) throws BundleException {
+ List<Bundle> installedBundles = new ArrayList<Bundle>();
+ logger.info("Installing bundles into the OSGi Framework");
+ for (URI bundleURI : bundlesURIs) {
+ installedBundles.add(installBundle(bundleURI));
+ }
+ return installedBundles;
+ }
+
+ /**
+ * Installs the bundle specified by the URI into the framework.
+ *
+ * @param bundleURI
+ * the URI of the bundle to install
+ * @return the installed bundle
+ * @throws BundleException
+ * if the bundle could not be installed
+ */
+ public Bundle installBundle(URI bundleURI) throws BundleException {
+ logger.fine("Installing bundle " + bundleURI);
+ return context.installBundle(bundleURI.toASCIIString());
+ }
+
+ /**
+ * Starts the bundles.
+ *
+ * If a bundle is a fragment bundle that bundle is not started.
+ *
+ * @param bundles
+ * the bundles to start
+ * @throws BundleException
+ * if a bundle could not be started
+ */
+ public void startBundles(List<Bundle> bundles) throws BundleException {
+ logger.info("Starting bundles in the OSGi Framework");
+ for (Bundle bundle : bundles) {
+ startBundle(bundle);
+ }
+ }
+
+ /**
+ * Starts the bundle.
+ *
+ * If the bundle is a fragment bundle the bundle is not started.
+ *
+ * @param bundle
+ * the bundle to start
+ * @throws BundleException
+ * if the bundle could not be started
+ */
+ public void startBundle(Bundle bundle) throws BundleException {
+ if (bundle.getHeaders().get(Constants.FRAGMENT_HOST) == null) {
+ logger.fine("Starting bundle " + bundle);
+ bundle.start();
+ }
+ }
+
+ /**
+ * Returns the context. Returns <code>null</code> if the framework is not started.
+ *
+ * @return the context
+ */
+ public BundleContext getContext() {
+ return context;
+ }
+
+ /**
+ * Sets the configuration to use when creating the OSGi framework.
+ *
+ * @param frameworkConfiguration the configuration to use when creating the OSGi framework
+ */
+ public void setFrameworkConfiguration(Map<String, String> frameworkConfiguration) {
+ this.frameworkConfiguration = frameworkConfiguration;
+ }
+
+ /**
+ * Adds boot delegation packages.
+ *
+ * Multiple packages must be separated by a ','.
+ *
+ * @param additionalBootDelegationPackages
+ * boot delegation packages to add
+ */
+ public void addBootDelegationPackages(String additionalBootDelegationPackages) {
+ String bootDelegationPackages = frameworkConfiguration
+ .get(Constants.FRAMEWORK_BOOTDELEGATION);
+ if (bootDelegationPackages == null || bootDelegationPackages.isEmpty()) {
+ bootDelegationPackages = additionalBootDelegationPackages;
+ } else {
+ bootDelegationPackages = bootDelegationPackages + ","
+ + additionalBootDelegationPackages;
+ }
+ frameworkConfiguration.put(Constants.FRAMEWORK_BOOTDELEGATION, bootDelegationPackages);
+ }
+
+ /**
+ * Sets the boot delegation packages.
+ *
+ * Multiple packages must be separated by a ','.
+ *
+ * @param bootDelegationPackages
+ * the boot delegation packages
+ */
+ public void setBootDelegationPackages(String bootDelegationPackages) {
+ frameworkConfiguration.put(Constants.FRAMEWORK_BOOTDELEGATION, bootDelegationPackages);
+ }
+
+ /**
+ * Adds system packages.
+ *
+ * Multiple packages must be separated by a ','.
+ *
+ * @param additionalSystemPackages
+ * system packages to add
+ */
+ public void addSystemPackages(String additionalSystemPackages) {
+ String systemPackages = frameworkConfiguration
+ .get(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA);
+ if (systemPackages == null || systemPackages.isEmpty()) {
+ systemPackages = additionalSystemPackages;
+ } else {
+ systemPackages = systemPackages + "," + additionalSystemPackages;
+ }
+ frameworkConfiguration.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, systemPackages);
+ }
+
+ /**
+ * Sets the system packages.
+ *
+ * Multiple packages must be separated by a ','.
+ *
+ * @param systemPackages
+ * the system packages
+ */
+ public void setSystemPackages(String systemPackages) {
+ frameworkConfiguration.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, systemPackages);
+ }
+
+ /**
+ * Sets the persistent storage area used by the framework.
+ *
+ * @param storageDirectory the persistent storage area used by the framework
+ */
+ public void setStorageDirectory(File storageDirectory) {
+ frameworkConfiguration.put(Constants.FRAMEWORK_STORAGE, storageDirectory.getAbsolutePath());
+ }
+
+ /**
+ * Set whether the storage directory should be cleaned on startup.
+ *
+ * @param cleanStorageDirectory
+ * whether the storage directory should be cleaned on startup
+ */
+ public void setCleanStorageDirectory(boolean cleanStorageDirectory) {
+ if (cleanStorageDirectory) {
+ frameworkConfiguration.put(Constants.FRAMEWORK_STORAGE_CLEAN,
+ Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
+ } else {
+ frameworkConfiguration.remove(Constants.FRAMEWORK_STORAGE_CLEAN);
+ }
+ }
+
+ /**
+ * Returns true if a bundle contains spring context files.
+ *
+ * @param bundle
+ * the bundle to check
+ * @return true if a bundle contains spring context files
+ */
+ private boolean hasSpringContext(Bundle bundle) {
+ String springFilesLocation = "META-INF/spring";
+ // check for custom spring files location
+ @SuppressWarnings("rawtypes")
+ Dictionary headers = bundle.getHeaders();
+ if (headers != null) {
+ Object header = headers.get("Spring-Context");
+ if (header != null) {
+ springFilesLocation = header.toString().trim();
+ }
+ }
+ @SuppressWarnings("rawtypes")
+ Enumeration springFiles = bundle.findEntries(springFilesLocation, "*.xml", false);
+ return springFiles != null && springFiles.hasMoreElements();
+ }
+
+ private synchronized void waitForSpringContext(BundleContext context, String springContext,
+ long timeoutSeconds) {
+ long timeLeftToWait = timeoutSeconds * 1000;
+ long startTime = System.currentTimeMillis();
+
+ while (!startedSpringContexts.contains(springContext) && timeLeftToWait > 0) {
+ try {
+ wait(timeLeftToWait);
+ } catch (InterruptedException e) {}
+ timeLeftToWait = timeLeftToWait - (System.currentTimeMillis() - startTime);
+ }
+ }
+
+ private synchronized void addStartedSpringContext(String springContext) {
+ startedSpringContexts.add(springContext);
+ notifyAll();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..32bd337
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,46 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.taverna</groupId>
+ <artifactId>taverna-parent</artifactId>
+ <version>1-incubating-SNAPSHOT</version>
+ </parent>
+ <groupId>org.apache.taverna.osgi</groupId>
+ <artifactId>taverna-osgi</artifactId>
+ <version>0.2.0-incubating-SNAPSHOT</version>
+ <name>Apache Taverna OSGi plugin system</name>
+ <description>OSGi-based plugin system, including
+ online updates. Written for Apache Taverna,
+ usable for any OSGi-based
+ command line/desktop product</description>
+ <packaging>pom</packaging>
+ <modules>
+ <module>xml-parser-service</module>
+ <module>xml-transformer-service</module>
+ <module>osgi-launcher</module>
+ <module>taverna-app-configuration-api</module>
+ <module>taverna-app-configuration-impl</module>
+ <module>taverna-configuration-api</module>
+ <module>taverna-configuration-impl</module>
+ <module>taverna-download-api</module>
+ <module>taverna-download-impl</module>
+ <module>taverna-maven-plugin</module>
+ <module>taverna-plugin-api</module>
+ <module>taverna-plugin-impl</module>
+ <module>taverna-update-api</module>
+ <module>taverna-update-impl</module>
+ <module>taverna-osgi-schemas</module>
+ </modules>
+ <repositories>
+ <repository>
+ <id>taverna-incubating</id>
+ <name>Apache Taverna incubating Repository</name>
+ <url>http://repository.mygrid.org.uk/artifactory/incubator-snapshot-local/</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots />
+ </repository>
+ </repositories>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-app-configuration-api/.project
----------------------------------------------------------------------
diff --git a/taverna-app-configuration-api/.project b/taverna-app-configuration-api/.project
new file mode 100644
index 0000000..dabe905
--- /dev/null
+++ b/taverna-app-configuration-api/.project
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>taverna-app-configuration-api</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-app-configuration-api/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-app-configuration-api/pom.xml b/taverna-app-configuration-api/pom.xml
new file mode 100644
index 0000000..020cea7
--- /dev/null
+++ b/taverna-app-configuration-api/pom.xml
@@ -0,0 +1,19 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.taverna.osgi</groupId>
+ <artifactId>taverna-osgi</artifactId>
+ <version>0.2.0-incubating-SNAPSHOT</version>
+ </parent>
+ <artifactId>taverna-app-configuration-api</artifactId>
+ <packaging>bundle</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>taverna-osgi-schemas</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ </dependencies>
+ <name>Apache Taverna App Configuration API</name>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-app-configuration-api/src/main/java/uk/org/taverna/configuration/app/ApplicationConfiguration.java
----------------------------------------------------------------------
diff --git a/taverna-app-configuration-api/src/main/java/uk/org/taverna/configuration/app/ApplicationConfiguration.java b/taverna-app-configuration-api/src/main/java/uk/org/taverna/configuration/app/ApplicationConfiguration.java
new file mode 100644
index 0000000..b372598
--- /dev/null
+++ b/taverna-app-configuration-api/src/main/java/uk/org/taverna/configuration/app/ApplicationConfiguration.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (C) 2012 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package uk.org.taverna.configuration.app;
+
+import java.io.File;
+
+import uk.org.taverna.commons.profile.xml.jaxb.ApplicationProfile;
+
+/**
+ * Represent the application config as it has been specified in
+ * {@value #PROPERTIES}. This configuration specifies the application's name
+ * and title, etc.
+ * <p>
+ * An application would typically provide the {@value #PROPERTIES} file on the classpath under
+ * a <code>conf</code> directory, or in a <code>conf</code> directory in the
+ * application's distribution directory.
+ *
+ * @author Stian Soiland-Reyes
+ * @author David Withers
+ */
+public interface ApplicationConfiguration {
+
+ public static final String CONF_DIR = "conf/";
+ public static final String PLUGINS_DIR = "plugins";
+
+ public String getName();
+
+ public String getTitle();
+
+ public File getStartupDir();
+
+ public File getApplicationHomeDir();
+
+ public File getUserPluginDir();
+
+ public File getSystemPluginDir();
+
+ public File getLogFile();
+
+ public File getLogDir();
+
+ public ApplicationProfile getApplicationProfile();
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-app-configuration-impl/.project
----------------------------------------------------------------------
diff --git a/taverna-app-configuration-impl/.project b/taverna-app-configuration-impl/.project
new file mode 100644
index 0000000..477b70d
--- /dev/null
+++ b/taverna-app-configuration-impl/.project
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>taverna-app-configuration-impl</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-app-configuration-impl/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-app-configuration-impl/pom.xml b/taverna-app-configuration-impl/pom.xml
new file mode 100644
index 0000000..55bab09
--- /dev/null
+++ b/taverna-app-configuration-impl/pom.xml
@@ -0,0 +1,43 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.taverna.osgi</groupId>
+ <artifactId>taverna-osgi</artifactId>
+ <version>0.2.0-incubating-SNAPSHOT</version>
+ </parent>
+ <packaging>bundle</packaging>
+ <artifactId>taverna-app-configuration-impl</artifactId>
+ <name>Apache Taverna App Configuration implementation</name>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Import-Package>uk.org.taverna.configuration.app;provide:=true,*</Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>taverna-app-configuration-api</artifactId>
+ <version>${project.parent.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>taverna-osgi-schemas</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>${log4j.version}</version>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-app-configuration-impl/src/main/java/uk/org/taverna/configuration/app/impl/ApplicationConfigurationImpl.java
----------------------------------------------------------------------
diff --git a/taverna-app-configuration-impl/src/main/java/uk/org/taverna/configuration/app/impl/ApplicationConfigurationImpl.java b/taverna-app-configuration-impl/src/main/java/uk/org/taverna/configuration/app/impl/ApplicationConfigurationImpl.java
new file mode 100644
index 0000000..b45f36f
--- /dev/null
+++ b/taverna-app-configuration-impl/src/main/java/uk/org/taverna/configuration/app/impl/ApplicationConfigurationImpl.java
@@ -0,0 +1,293 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package uk.org.taverna.configuration.app.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+import java.util.UUID;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.commons.profile.xml.jaxb.ApplicationProfile;
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+
+/**
+ * Represent the application config as it has been specified in {@value #PROPERTIES}. This
+ * configuration specifies the application's name and title, etc.
+ * <p>
+ * An application would typically provide the {@value #PROPERTIES} file on the classpath under a
+ * <code>conf</code> directory, or in a <code>conf</code> directory in the application's
+ * distribution directory.
+ *
+ * @author Stian Soiland-Reyes
+ * @author David Withers
+ */
+public class ApplicationConfigurationImpl implements ApplicationConfiguration {
+
+ private static final Logger logger = Logger.getLogger(ApplicationConfigurationImpl.class);
+
+ private static final String UNKNOWN_APPLICATION = "unknownApplication-"
+ + UUID.randomUUID().toString();
+
+ public static final String APP_HOME = "taverna.app.home";
+ public static final String APP_STARTUP = "taverna.app.startup";
+ public static final String APPLICATION_PROFILE = "ApplicationProfile.xml";
+
+ private File startupDir;
+ private File homeDir;
+
+ private ApplicationProfile applicationProfile;
+ private ApplicationProfile defaultApplicationProfile;
+
+ public ApplicationConfigurationImpl() {
+ }
+
+ @Override
+ public String getName() {
+ String name = null;
+ ApplicationProfile profile = getDefaultApplicationProfile();
+ if (profile != null) {
+ name = profile.getName();
+ }
+ if (name == null) {
+ logger.error("ApplicationConfig could not determine application name, using "
+ + UNKNOWN_APPLICATION);
+ return UNKNOWN_APPLICATION;
+ }
+ return name;
+ }
+
+ @Override
+ public String getTitle() {
+ return getName();
+ }
+
+ @Override
+ public File getStartupDir() {
+ if (startupDir == null) {
+ String startupDirName = System.getProperty(APP_STARTUP);
+ if (startupDirName != null) {
+ startupDir = new File(startupDirName).getAbsoluteFile();
+ }
+ }
+ return startupDir;
+ }
+
+ @Override
+ public synchronized File getApplicationHomeDir() {
+ if (homeDir == null) {
+ if (getName().equals(ApplicationConfigurationImpl.UNKNOWN_APPLICATION)) {
+ try {
+ // Make a temporary home directory as a backup
+ homeDir = File.createTempFile(getName(), "home");
+ homeDir.delete();
+ homeDir.mkdirs();
+ } catch (IOException e) {
+ throw new IllegalStateException("Can't create temporary application home", e);
+ }
+ logger.warn("Could not determine application's user home,"
+ + " using temporary dir " + homeDir);
+ } else {
+ homeDir = new ApplicationUserHome(getName(), System.getProperty(APP_HOME)).getAppUserHome();
+ }
+ if (homeDir == null || !homeDir.isDirectory()) {
+ throw new IllegalStateException("Could not create application home directory "
+ + homeDir);
+ }
+ }
+ return homeDir;
+ }
+
+ @Override
+ public File getUserPluginDir() {
+ File userPluginsDir = new File(getApplicationHomeDir(), PLUGINS_DIR);
+ try {
+ userPluginsDir.mkdirs();
+ } catch (SecurityException e) {
+ logger.warn("Error creating user plugin directory at " + userPluginsDir, e);
+ }
+ return userPluginsDir;
+ }
+
+ @Override
+ public File getSystemPluginDir() {
+ File systemPluginsDir = new File(getStartupDir(), PLUGINS_DIR);
+ try {
+ systemPluginsDir.mkdirs();
+ } catch (SecurityException e) {
+ logger.debug("Error creating system plugin directory at " + systemPluginsDir, e);
+ }
+ return systemPluginsDir;
+ }
+
+ @Override
+ public File getLogFile() {
+ return new File(getLogDir(), getName() + ".log");
+ }
+
+ @Override
+ public File getLogDir() {
+ File logDir = new File(getApplicationHomeDir(), "logs");
+ logDir.mkdirs();
+ if (!logDir.isDirectory()) {
+ throw new IllegalStateException("Could not create log directory " + logDir);
+ }
+ return logDir;
+ }
+
+ private void findInClassLoader(List<URI> configs, ClassLoader classLoader, String resourcePath) {
+ Enumeration<URL> resources;
+ try {
+ resources = classLoader.getResources(resourcePath);
+ } catch (IOException ex) {
+ System.err.println("Error looking for " + resourcePath + " in " + classLoader);
+ ex.printStackTrace();
+ return;
+ }
+ while (resources.hasMoreElements()) {
+ URL configURL = resources.nextElement();
+ try {
+ configs.add(configURL.toURI());
+ } catch (URISyntaxException ex) {
+ throw new RuntimeException("Invalid URL from getResource(): " + configURL, ex);
+ }
+ }
+ }
+
+ /**
+ * Attempt to load application properties from propertyFileName.
+ * <p>
+ * Will attempt to load a property file from the locations below. The first non-empty properties
+ * successfully loaded will be returned.
+ * <ol>
+ * <li>$startup/conf/$resourceName</li>
+ * <li>$startup/$resourceName</li>
+ * <li>$contextClassPath/conf/$resourceName</li>
+ * <li>$contextClassPath/$resourceName</li>
+ * <li>$classpath/conf/$resourceName</li>
+ * <li>$classpath/$resourceName</li>
+ * </ol>
+ * <p>
+ * Where <code>$startup</code> is this application's startup directory as determined by
+ * {@link #getStartupDir()}, and <code>$contextClassPath</code> means a search using
+ * {@link ClassLoader#getResources(String)} from the classloader returned by
+ * {@link Thread#getContextClassLoader()} and then again <code>$classpath</code> for the
+ * classloader of {@link #getClass()} of this instance.
+ * </p>
+ * <p>
+ * If none of these sources could find a non-empty property file, a warning is logged, and an
+ * empty {@link Properties} instance is returned.
+ *
+ * @param resourceName
+ * Relative filename of property file
+ *
+ * @return Loaded or empty {@link Properties} instance.
+ */
+ protected Properties loadProperties(String resourceName) {
+ // Ordered list of config locations to attempt to load
+ // properties from
+ List<URI> configs = new ArrayList<URI>();
+
+ File startupDir = getStartupDir();
+ if (startupDir != null) {
+ configs.add(startupDir.toURI().resolve(CONF_DIR).resolve(resourceName));
+ configs.add(startupDir.toURI().resolve(resourceName));
+ }
+
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ findInClassLoader(configs, contextClassLoader, CONF_DIR + resourceName);
+ findInClassLoader(configs, contextClassLoader, resourceName);
+
+ findInClassLoader(configs, getClass().getClassLoader(), CONF_DIR + resourceName);
+ findInClassLoader(configs, getClass().getClassLoader(), resourceName);
+
+ Properties loadedProps = new Properties();
+ for (URI config : configs) {
+ try {
+ InputStream inputStream = config.toURL().openStream();
+ loadedProps.load(inputStream);
+ } catch (MalformedURLException ex) {
+ throw new RuntimeException("Invalid URL from URI: " + config, ex);
+ } catch (IOException ex) {
+ continue; // Probably not found/access denied
+ }
+ if (!loadedProps.isEmpty()) {
+ logger.debug("Loaded " + resourceName + " from " + config);
+ return loadedProps;
+ }
+ }
+ logger.debug("Could not find application properties file " + resourceName);
+ return loadedProps;
+ }
+
+ @Override
+ public ApplicationProfile getApplicationProfile() {
+ if (applicationProfile == null) {
+ File applicationProfileFile = new File(getApplicationHomeDir(), APPLICATION_PROFILE);
+ if (!applicationProfileFile.exists()) {
+ logger.debug("Application profile not found at " + applicationProfileFile);
+ return getDefaultApplicationProfile();
+ }
+ try {
+ JAXBContext jaxbContext = JAXBContext.newInstance(ApplicationProfile.class);
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ applicationProfile = (ApplicationProfile) unmarshaller.unmarshal(applicationProfileFile);
+ } catch (JAXBException e) {
+ logger.error("Could not read application profile from " + applicationProfileFile, e);
+ }
+ if (applicationProfile == null) {
+ logger.debug("Application profile not found at " + applicationProfileFile);
+ return getDefaultApplicationProfile();
+ }
+ }
+ return applicationProfile;
+ }
+
+ public ApplicationProfile getDefaultApplicationProfile() {
+ if (defaultApplicationProfile == null) {
+ File applicationProfileFile = new File(getStartupDir(), APPLICATION_PROFILE);
+ if (applicationProfileFile.exists()) {
+ try {
+ JAXBContext jaxbContext = JAXBContext.newInstance(ApplicationProfile.class);
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ defaultApplicationProfile = (ApplicationProfile) unmarshaller.unmarshal(applicationProfileFile);
+ } catch (JAXBException e) {
+ throw new IllegalStateException("Could not read application profile from " + applicationProfileFile);
+ }
+ }
+ }
+ return defaultApplicationProfile;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-app-configuration-impl/src/main/java/uk/org/taverna/configuration/app/impl/ApplicationUserHome.java
----------------------------------------------------------------------
diff --git a/taverna-app-configuration-impl/src/main/java/uk/org/taverna/configuration/app/impl/ApplicationUserHome.java b/taverna-app-configuration-impl/src/main/java/uk/org/taverna/configuration/app/impl/ApplicationUserHome.java
new file mode 100644
index 0000000..a5bf207
--- /dev/null
+++ b/taverna-app-configuration-impl/src/main/java/uk/org/taverna/configuration/app/impl/ApplicationUserHome.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package uk.org.taverna.configuration.app.impl;
+
+import java.io.File;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Find and create an application's user directory according to operating system
+ * standards.
+ * <p>
+ * For example for the application "MyApp" this class will be able to find
+ * <code>$HOME/.myapp</code> on Linux or
+ * <code>C:\Document and settings\MyUsername\Application Data\MyApplication</code>
+ * on Windows XP.
+ *
+ * @author Stian Soiland-Reyes
+ * @author Stuart Owen
+ *
+ */
+public class ApplicationUserHome {
+
+ private final String defaultApplicationHome;
+
+ private final String applicationName;
+
+ private File homeDir;
+
+ private static Logger logger = Logger.getLogger(ApplicationUserHome.class);
+
+ /**
+ * Initialise with the name of the application.
+ *
+ * @param applicationName
+ * This name will be used as a template for creating the
+ * application home directory (but might be transcribed, for
+ * instance to lowercase). It is generally recommended, but not
+ * required - that this name does not contain spaces or any
+ * special international/Unicode characters.
+ */
+ public ApplicationUserHome(String applicationName) {
+ this(applicationName, null);
+ }
+
+ /**
+ * Initialise with the name of the application and a default application
+ * home.
+ *
+ * @param applicationName
+ * This name will be used as a template for creating the
+ * application home directory (but might be transcribed, for
+ * instance to lowercase). It is generally recommended, but not
+ * required - that this name does not contain spaces or any
+ * special international/Unicode characters.
+ * @param defaultApplicationHome
+ * The full path to the default home directory. If this string is
+ * not <code>null</code>, then a {@link File} based on this
+ * directory will always be returned by
+ * {@link #getDefaultApplicationHome()} - otherwise the normal
+ * operating system logic is used to determine the application's
+ * home directory.
+ */
+ public ApplicationUserHome(String applicationName,
+ String defaultApplicationHome) {
+ this.applicationName = applicationName;
+ this.defaultApplicationHome = defaultApplicationHome;
+ }
+
+ /**
+ * Find (and if necessary create) the user's application directory,
+ * according to operating system standards. The resolved directory is then
+ * returned as a {@link File} object.
+ * <p>
+ * The application's name as defined by {@link #getApplicationName()} is
+ * used as a basis for naming the directory of the application's user
+ * directory, but the directory name might for instance be transformed to
+ * lowercase.
+ * <p>
+ * If {@link #getDefaultApplicationHome()} returns a non-null value, the
+ * directory specified by that path will be used instead of the operation
+ * system specific directory. The directory will be created if needed.
+ * <p>
+ * If any exception occurs (such as out of diskspace), <code>null</code>
+ * will be returned.
+ *
+ * <p>
+ * On Windows XP, this will typically be something like:
+ *
+ * <pre>
+ * C:\Document and settings\MyUsername\Application Data\MyApplication
+ * </pre>
+ *
+ * and on Windows Vista it would be something like:
+ *
+ * <pre>
+ * C:\Users\MyUsername\Application Data\MyApplication
+ * </pre>
+ *
+ * while on Mac OS X it will be something like:
+ *
+ * <pre>
+ * /Users/MyUsername/Library/Application Support/MyApplication
+ * </pre>
+ *
+ * All other OS'es are assumed to be UNIX-alike, returning something like:
+ *
+ * <pre>
+ * /user/myusername/.myapplication
+ * </pre>
+ *
+ * <p>
+ * If the directory does not already exist, it will be created.
+ * </p>
+ *
+ * @return An {@link File} referring to an existing directory for
+ * user-specific configuration etc. for the given application.
+ */
+ public synchronized File getAppUserHome() {
+ if (homeDir != null) {
+ return homeDir;
+ }
+ File appHome;
+ String applicationHome = getDefaultApplicationHome();
+ if (applicationHome != null) {
+ appHome = new File(applicationHome);
+ } else {
+ if (getApplicationName() == null) {
+ logger.warn("Unknown application name");
+ return null;
+ }
+ File home = new File(System.getProperty("user.home"));
+ if (!home.isDirectory()) {
+ logger.error("User home not a valid directory: " + home);
+ return null;
+ }
+ String os = System.getProperty("os.name");
+ // logger.debug("OS is " + os);
+ if (os.equals("Mac OS X")) {
+ File libDir = new File(home, "Library/Application Support");
+ libDir.mkdirs();
+ appHome = new File(libDir, getApplicationName());
+ } else if (os.startsWith("Windows")) {
+ String APPDATA = System.getenv("APPDATA");
+ File appData = null;
+ if (APPDATA != null) {
+ appData = new File(APPDATA);
+ }
+ if (appData != null && appData.isDirectory()) {
+ appHome = new File(appData, getApplicationName());
+ } else {
+ logger.warn("Could not find %APPDATA%: " + APPDATA);
+ appHome = new File(home, getApplicationName());
+ }
+ } else {
+ // We'll assume UNIX style is OK
+ appHome = new File(home, "."
+ + getApplicationName().toLowerCase().replace(' ', '-'));
+ }
+ }
+ if (!appHome.exists()) {
+ if (appHome.mkdir()) {
+ logger.info("Created " + appHome);
+ } else {
+ logger.error("Could not create " + appHome);
+ return null;
+ }
+ }
+ if (!appHome.isDirectory()) {
+ logger.error("User home not a valid directory: " + appHome);
+ return null;
+ }
+ this.homeDir = appHome.getAbsoluteFile();
+ return this.homeDir;
+ }
+
+ /**
+ * The application's name. This name will be used as a template for creating
+ * the application home directory (but might be transcribed, for instance to
+ * lowercase). It is generally recommended, but not required - that this
+ * name does not contain spaces or any special international/Unicode
+ * characters.
+ *
+ * @return The application's name.
+ *
+ */
+ public String getApplicationName() {
+ return applicationName;
+ }
+
+ /**
+ * The full path to the default home directory. If this string is not
+ * <code>null</code>, then a {@link File} based on this directory will
+ * always be returned by {@link #getDefaultApplicationHome()} - otherwise
+ * the normal operating system logic is used to determine the application's
+ * home directory.
+ *
+ * @return The full path to the application's home directory, or
+ * <code>null</code> if the operation system specific logic is to
+ * be used.
+ */
+ public String getDefaultApplicationHome() {
+ return defaultApplicationHome;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-app-configuration-impl/src/main/java/uk/org/taverna/configuration/app/impl/Log4JConfiguration.java
----------------------------------------------------------------------
diff --git a/taverna-app-configuration-impl/src/main/java/uk/org/taverna/configuration/app/impl/Log4JConfiguration.java b/taverna-app-configuration-impl/src/main/java/uk/org/taverna/configuration/app/impl/Log4JConfiguration.java
new file mode 100644
index 0000000..f0e88c2
--- /dev/null
+++ b/taverna-app-configuration-impl/src/main/java/uk/org/taverna/configuration/app/impl/Log4JConfiguration.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package uk.org.taverna.configuration.app.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.PatternLayout;
+import org.apache.log4j.PropertyConfigurator;
+import org.apache.log4j.RollingFileAppender;
+
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+
+public class Log4JConfiguration {
+ public final static String LOG4J_PROPERTIES = "log4j.properties";
+
+ private static boolean log4jConfigured = false;
+
+ private ApplicationConfiguration applicationConfiguration;
+
+ private Properties properties ;
+
+ public Log4JConfiguration() {
+// prepareLog4J();
+ }
+
+ public void prepareLog4J() {
+ if (!log4jConfigured) {
+ Properties log4jProperties = getLogProperties();
+ if (log4jProperties != null && ! log4jProperties.isEmpty()) {
+ LogManager.resetConfiguration();
+ PropertyConfigurator.configure(log4jProperties);
+ }
+
+ String logFilePath = applicationConfiguration.getLogFile().getAbsolutePath();
+ PatternLayout layout = new PatternLayout("%-5p %d{ISO8601} (%c:%L) - %m%n");
+
+ // Add file appender
+ RollingFileAppender appender;
+ try {
+ appender = new RollingFileAppender(layout, logFilePath);
+ appender.setMaxFileSize("1MB");
+ appender.setEncoding("UTF-8");
+ appender.setMaxBackupIndex(4);
+ // Let root logger decide level
+ appender.setThreshold(Level.ALL);
+ LogManager.getRootLogger().addAppender(appender);
+ } catch (IOException e) {
+ System.err.println("Could not log to " + logFilePath);
+ }
+
+ log4jConfigured = true;
+ }
+ }
+
+ /**
+ * Initialises and provides access to the list of Properties.
+ * @return
+ */
+ public Properties getLogProperties() {
+ if (properties == null) {
+ InputStream is = getLogPropertiesInputStream();
+ if (is != null) {
+ try {
+ properties = new Properties();
+ properties.load(is);
+// properties.putAll(System.getProperties());
+ } catch (IOException e) {
+ errorLog("An error occurred trying to load the " + LOG4J_PROPERTIES + " file",e);
+ }
+ }
+ }
+ return properties;
+ }
+
+ /**
+ * Return an input stream to the configuration file, or null if it can't be found
+ * @return
+ */
+ private InputStream getLogPropertiesInputStream() {
+ InputStream result = null;
+ File propertiesFile = getLogPropertiesFile();
+ if (propertiesFile!=null) {
+ try {
+ result=new FileInputStream(propertiesFile);
+ } catch (FileNotFoundException e) {
+ errorLog("Unable to find "+LOG4J_PROPERTIES,e);
+ }
+ }
+ else {
+ errorLog("Unable to determine file for "+LOG4J_PROPERTIES,null);
+ }
+ return result;
+ }
+
+ /**
+ * Returns a File object to the configuration file or null if it cannot be found.
+ *
+ * @return
+ */
+ private File getLogPropertiesFile() {
+ File home = applicationConfiguration.getApplicationHomeDir();
+ File startup = applicationConfiguration.getStartupDir();
+ File result=null;
+ if (home!=null) {
+ File file = new File(new File(home, ApplicationConfiguration.CONF_DIR), LOG4J_PROPERTIES);
+ if (file.exists()) {
+ result=file;
+ }
+ }
+ if (result==null && startup!=null) {
+ File file = new File(new File(startup, ApplicationConfiguration.CONF_DIR), LOG4J_PROPERTIES);
+ if (file.exists()) {
+ result=file;
+ }
+ }
+ return result;
+ }
+
+ private void errorLog(String message, Throwable exception) {
+ System.out.println(message);
+ if (exception!=null) {
+ exception.printStackTrace();
+ }
+
+ }
+
+ /**
+ * Sets the applicationConfiguration.
+ *
+ * @param applicationConfiguration the new value of applicationConfiguration
+ */
+ public void setApplicationConfiguration(ApplicationConfiguration applicationConfiguration) {
+ this.applicationConfiguration = applicationConfiguration;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-app-configuration-impl/src/main/resources/META-INF/spring/configuration-context-osgi.xml
----------------------------------------------------------------------
diff --git a/taverna-app-configuration-impl/src/main/resources/META-INF/spring/configuration-context-osgi.xml b/taverna-app-configuration-impl/src/main/resources/META-INF/spring/configuration-context-osgi.xml
new file mode 100644
index 0000000..86cb988
--- /dev/null
+++ b/taverna-app-configuration-impl/src/main/resources/META-INF/spring/configuration-context-osgi.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:beans="http://www.springframework.org/schema/beans"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/osgi
+ http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+ <service ref="applicationConfiguration" interface="uk.org.taverna.configuration.app.ApplicationConfiguration" />
+
+</beans:beans>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-app-configuration-impl/src/main/resources/META-INF/spring/configuration-context.xml
----------------------------------------------------------------------
diff --git a/taverna-app-configuration-impl/src/main/resources/META-INF/spring/configuration-context.xml b/taverna-app-configuration-impl/src/main/resources/META-INF/spring/configuration-context.xml
new file mode 100644
index 0000000..db9645e
--- /dev/null
+++ b/taverna-app-configuration-impl/src/main/resources/META-INF/spring/configuration-context.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+ <bean id="applicationConfiguration" class="uk.org.taverna.configuration.app.impl.ApplicationConfigurationImpl" />
+ <bean id="log4JConfiguration" class="uk.org.taverna.configuration.app.impl.Log4JConfiguration" init-method="prepareLog4J">
+ <property name="applicationConfiguration">
+ <ref local="applicationConfiguration" />
+ </property>
+ </bean>
+
+</beans>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-configuration-api/.project
----------------------------------------------------------------------
diff --git a/taverna-configuration-api/.project b/taverna-configuration-api/.project
new file mode 100644
index 0000000..38755c1
--- /dev/null
+++ b/taverna-configuration-api/.project
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>taverna-configuration-api</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-configuration-api/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-configuration-api/pom.xml b/taverna-configuration-api/pom.xml
new file mode 100644
index 0000000..a2b6460
--- /dev/null
+++ b/taverna-configuration-api/pom.xml
@@ -0,0 +1,30 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.taverna.osgi</groupId>
+ <artifactId>taverna-osgi</artifactId>
+ <version>0.2.0-incubating-SNAPSHOT</version>
+ </parent>
+ <artifactId>taverna-configuration-api</artifactId>
+ <name>Apache Taverna Configuration API</name>
+ <packaging>bundle</packaging>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>com.springsource.org.apache.commons.csv</artifactId>
+ <version>${apache.commons.csv.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>${log4j.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>${junit.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-configuration-api/src/main/java/uk/org/taverna/configuration/AbstractConfigurable.java
----------------------------------------------------------------------
diff --git a/taverna-configuration-api/src/main/java/uk/org/taverna/configuration/AbstractConfigurable.java b/taverna-configuration-api/src/main/java/uk/org/taverna/configuration/AbstractConfigurable.java
new file mode 100644
index 0000000..a00938f
--- /dev/null
+++ b/taverna-configuration-api/src/main/java/uk/org/taverna/configuration/AbstractConfigurable.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package uk.org.taverna.configuration;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVPrinter;
+import org.apache.log4j.Logger;
+
+/**
+ * A utility abstract class that simplifies implementing a Configurable.
+ * <br>
+ * <p>A concrete version of this class needs to define the name,category,
+ * UUID string and the set of default values.</p>
+ *
+ * @author Stuart Owen
+ *
+ */
+public abstract class AbstractConfigurable implements Configurable {
+
+ private Map<String,String> propertyMap = new HashMap<String, String>();
+
+ private static Logger logger = Logger.getLogger(AbstractConfigurable.class);
+
+ public static final String DELETED_VALUE_CODE = "~~DELETED~~";
+
+ private ConfigurationManager configurationManager;
+
+ public Set<String> getKeys() {
+ return getInternalPropertyMap().keySet();
+ }
+
+ /**
+ * Constructs the AbstractConfigurable by either reading from a previously stored set of properties,
+ * or by using the default values which results in them being stored for subsequent usage.
+ */
+ public AbstractConfigurable(ConfigurationManager configurationManager) {
+ this.configurationManager = configurationManager;
+ try {
+ configurationManager.populate(this);
+ } catch (Exception e) {
+ logger.error("There was an error reading the properties for the Configurable:"+getFilePrefix(),e);
+ }
+ }
+
+ public synchronized String getProperty(String key) {
+ String val = getInternalPropertyMap().get(key);
+ if (val==null) val=getDefaultProperty(key);
+ if (DELETED_VALUE_CODE.equals(val)) val=null;
+ return val;
+ }
+
+ public String getDefaultProperty(String key) {
+ return getDefaultPropertyMap().get(key);
+ }
+
+ protected void store() {
+ try {
+ configurationManager.store(this);
+ } catch (Exception e) {
+ logger.error("There was an error storing the new configuration for: "+this.getFilePrefix(),e);
+ }
+ }
+
+ public void clear() {
+ getInternalPropertyMap().clear();
+ }
+
+ public synchronized void setProperty(String key, String value) {
+ Object oldValue = getInternalPropertyMap().get(key);
+ if (value==null) {
+ deleteProperty(key);
+ }
+ else {
+ getInternalPropertyMap().put(key,value);
+ }
+ if (value==null || !value.equals(oldValue)) {
+ store();
+ }
+ }
+
+ /**
+ * Provides access to the internal map.
+ * <br>
+ * Note that this map will contain entries for deleted values that also have corresponding default values.
+ * For this reason using this map directly is discouraged, and #getProperty(String)} should be used instead.
+ * @return
+ */
+ public Map<String, String> getInternalPropertyMap() {
+ return propertyMap;
+ }
+
+
+ public void restoreDefaults() {
+ propertyMap.clear();
+ propertyMap.putAll(getDefaultPropertyMap());
+ store();
+ }
+
+ public void deleteProperty(String key) {
+ if (getDefaultPropertyMap().containsKey(key)) {
+ propertyMap.put(key, DELETED_VALUE_CODE);
+ }
+ else {
+ propertyMap.remove(key);
+ }
+ }
+
+ /**
+ * Returns an unmodifiable List<String> for the given key. Internally the value is stored as a single String, but converted to a list when calling this method.
+ * <br>
+ * The list is unmodifiable to prevent the mistake of trying <pre>getPropertyStringList(..).add("new element");</pre> which will not affect the stored
+ * list. For the property to be updated this{@link #setPropertyStringList(String, List)} must be used.
+ */
+ public List<String> getPropertyStringList(String key) {
+ String value = getProperty(key);
+ if (value!=null) {
+ return Collections.unmodifiableList(fromListText(value));
+ }
+ else {
+ return null;
+ }
+ }
+
+ private List<String> fromListText(String property) {
+ List<String> result = new ArrayList<String>();
+ if (property.length()>0) { //an empty string as assumed to be an empty list, rather than a list with 1 empty string in it!
+ StringReader reader = new StringReader(property);
+ CSVParser csvReader = new CSVParser(reader);
+ try {
+ for (String v : csvReader.getLine()) {
+ result.add(v);
+ }
+ } catch (IOException e) {
+ logger.error("Exception occurred parsing CSV properties:"+property,e);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Set a value that is known to be a list. The value can be retrieved using this{@link #getPropertyStringList(String)}
+ * <br>
+ * Within the file, the value is stored as a single Comma Separated Value
+ */
+ public void setPropertyStringList(String key, List<String> value) {
+ setProperty(key, toListText(value));
+ }
+
+ private String toListText(List<String> values) {
+ StringWriter writer = new StringWriter();
+ CSVPrinter csvWriter = new CSVPrinter(writer);
+ csvWriter.println(values.toArray(new String[]{}));
+ return writer.getBuffer().toString().trim();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-configuration-api/src/main/java/uk/org/taverna/configuration/Configurable.java
----------------------------------------------------------------------
diff --git a/taverna-configuration-api/src/main/java/uk/org/taverna/configuration/Configurable.java b/taverna-configuration-api/src/main/java/uk/org/taverna/configuration/Configurable.java
new file mode 100644
index 0000000..b9b0642
--- /dev/null
+++ b/taverna-configuration-api/src/main/java/uk/org/taverna/configuration/Configurable.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package uk.org.taverna.configuration;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An interface that defines an Object as being configurable.
+ * It supports the core properties that allows this items configuration to be stored and re-populated by the ConfigurationManager
+ *
+ * @author Stuart Owen
+ *
+ */
+public interface Configurable {
+
+ /**
+ * @return a Map containing the default value/key pairs of the configured properties
+ */
+ Map<String,String> getDefaultPropertyMap();
+ /**
+ * @return a globally unique identifier that ensures that when stored this items configuration details will never clash with another
+ */
+ String getUUID();
+
+ /**
+ * @return a friendly name for the item
+ */
+ String getDisplayName();
+
+ /**
+ * return a file-system suitable prefix
+ */
+ String getFilePrefix();
+
+ /**
+ * @return a String defining the category of configurations that this item belongs to.
+ */
+ String getCategory();
+ /**
+ * Restore the default property map
+ */
+ void restoreDefaults();
+
+ /**
+ * Provides the default property for a given key
+ *
+ * @param key
+ * @return
+ */
+ String getDefaultProperty(String key);
+
+ Set<String> getKeys();
+
+ void clear();
+
+ /**
+ * Provides access to the internal map.
+ * <br>
+ * Note that this map may contain internal identifiers for deleted entries for deleted values that also have corresponding default values.
+ * For this reason using this map directly is discouraged, and #getProperty(String)} should be used instead.
+ * @return
+ */
+ Map<String, String> getInternalPropertyMap();
+
+ /**
+ * Looks up the property for the given key.
+ * <br>
+ * Using this method is preferable to using the property map directly.
+ * @param key
+ * @return the String represented by the key, the default value, or null
+ */
+ String getProperty(String key);
+
+ /**
+ * Overwrites or applies a new value against the given key in the property map.
+ * <br>
+ * Setting a value to null is equivalent to calling this{@link #deleteProperty(String)}
+ * <br>
+ * If the value is new, or changed, the the property map is stored.
+ * <br>
+ * Using this method is preferable to using the property map directly.
+ * @param key
+ * @param value
+ */
+ void setProperty(String key, String value);
+
+ /**
+ * Deletes a property value for a given key.
+ * <br>
+ * Subsequent calls to this{@link #getProperty(String)} will return null.
+ * @param key
+ */
+ void deleteProperty(String key);
+
+ public List<String> getPropertyStringList(String key);
+
+ public void setPropertyStringList(String key, List<String>value);
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-osgi/blob/c9bb093a/taverna-configuration-api/src/main/java/uk/org/taverna/configuration/ConfigurationManager.java
----------------------------------------------------------------------
diff --git a/taverna-configuration-api/src/main/java/uk/org/taverna/configuration/ConfigurationManager.java b/taverna-configuration-api/src/main/java/uk/org/taverna/configuration/ConfigurationManager.java
new file mode 100644
index 0000000..11ca22a
--- /dev/null
+++ b/taverna-configuration-api/src/main/java/uk/org/taverna/configuration/ConfigurationManager.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (C) 2011 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package uk.org.taverna.configuration;
+
+/**
+ * Handles the configuration for a {@link Configurable} object
+ *
+ * @author David Withers
+ */
+public interface ConfigurationManager {
+
+ /**
+ * Write out the properties configuration to disk based on the UUID of the
+ * {@link Configurable}
+ * <br>
+ * Default values are not stored within the file, but only those that have been changed or deleted.
+ *
+ * @param configurable
+ * @throws Exception
+ */
+ public void store(Configurable configurable) throws Exception;
+
+ /**
+ * Loads the configuration details from disk or from memory and populates the provided Configurable
+ *
+ * @param configurable
+ * @return
+ * @throws Exception
+ * if there are no configuration details available
+ */
+ public void populate(Configurable configurable) throws Exception;
+
+}
\ No newline at end of file