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