ace-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject svn commit: r1357570 [8/34] - in /ace/sandbox/marrs: cnf/ cnf/ext/ cnf/lib/ cnf/releaserepo/ cnf/repo/ cnf/repo/.obrcache/ cnf/repo/.obrcache/http%3A%2F%2Fbundles.bndtools.org.s3.amazonaws.com%2Fcom.jcraft.jsch/ cnf/repo/.obrcache/http%3A%2F%2Fbundles....
Date Thu, 05 Jul 2012 12:10:06 GMT
Added: ace/sandbox/marrs/org.apache.ace.builder/src/org/apache/ace/builder/DeploymentPackageBuilder.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.builder/src/org/apache/ace/builder/DeploymentPackageBuilder.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.builder/src/org/apache/ace/builder/DeploymentPackageBuilder.java (added)
+++ ace/sandbox/marrs/org.apache.ace.builder/src/org/apache/ace/builder/DeploymentPackageBuilder.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.builder;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+/**
+ * Builder for deployment packages. Can handle bundles, resource processors and artifacts. Uses
+ * the builder pattern:
+ * <pre>
+ * OutputStream out = new FileOutputStream("first.dp");
+ * DeploymentPackageBuilder.createDeploymentPackage("mydp", "1.0")
+ *     .addBundle(new URL("http://repository/api-1.1.0.jar"))
+ *     .addBundle(new URL("http://repository/impl-1.1.3.jar"))
+ *     .addResourceProcessor(new URL("http://repository/rp-1.0.2.jar"))
+ *     .addArtifact(new URL("http://artifacts/config/v1.jar"), "rp.pid")
+ *     .addArtifact(new URL("http://artifacts/data/v3.jar"), "rp.pid")
+ *     .generate(out);
+ * </pre>
+ * For bundles and resource processors, you can simply point to a valid URL and it will
+ * be queried for all required metadata. For artifacts, you need to specify both the URL
+ * and the PID of the resource processor. The builder will use the order you specify for
+ * bundles, resource processors and artifacts, but you don't have to specify all bundles
+ * and resource processors first and then all artifacts.
+ */
+public class DeploymentPackageBuilder {
+	private static final String PREFIX_BUNDLE = "bundle-";
+	private static final String PREFIX_ARTIFACT = "artifact-";
+	private static final int BUFFER_SIZE = 32 * 1024;
+	private final String m_symbolicName;
+	private final String m_version;
+	private final List<ArtifactData> m_bundles = new ArrayList<ArtifactData>();
+	private final List<ArtifactData> m_processors = new ArrayList<ArtifactData>();
+	private final List<ArtifactData> m_artifacts = new ArrayList<ArtifactData>();
+	private int m_id = 1;
+	
+	private DeploymentPackageBuilder(String symbolicName, String version) {
+		m_symbolicName = symbolicName;
+		m_version = version;
+	}
+	
+	/**
+	 * Creates a new deployment package.
+	 * 
+	 * @param name the name of the deployment package
+	 * @param version the version of the deployment package
+	 * @return a builder to further add data to the deployment package
+	 */
+	public static DeploymentPackageBuilder createDeploymentPackage(String name, String version) {
+		return new DeploymentPackageBuilder(name, version);
+	}
+	
+	/**
+	 * Adds a bundle to the deployment package.
+	 * 
+	 * @param url a url that refers to the bundle
+	 * @return a builder to further add data to the deployment package
+	 * @throws Exception if something goes wrong while building
+	 */
+	public DeploymentPackageBuilder addBundle(URL url) throws Exception {
+		return addBundleArtifact(url, false);
+	}
+	
+	/**
+	 * Adds a resource processor to the deployment package. A resource processor is a special
+	 * type of bundle.
+	 * 
+	 * @param url a url that refers to the resource processor
+	 * @return a builder to further add data to the deployment package
+	 * @throws Exception if something goes wrong while building
+	 */
+	public DeploymentPackageBuilder addResourceProcessor(URL url) throws Exception {
+		return addBundleArtifact(url, true);
+	}
+	
+	/**
+	 * Adds an artifact to the deployment package.
+	 * 
+	 * @param url a url that refers to the artifact
+	 * @param processorPID the PID of the processor for this artifact
+	 * @return a builder to further add data to the deployment package
+	 * @throws Exception if something goes wrong while building
+	 */
+	public DeploymentPackageBuilder addArtifact(URL url, String processorPID) throws Exception {
+		String path = url.getPath();
+		int i = path.lastIndexOf('/');
+		if (i > 0 && i < (path.length() - 1)) {
+			path = path.substring(i + 1);
+		}
+		String name = PREFIX_ARTIFACT + getUniqueID() + "-" + path;
+    	m_artifacts.add(ArtifactData.createArtifact(url, name, processorPID));
+		return this;
+	}
+
+	/**
+	 * Generates a deployment package and streams it to the output stream you provide. Before
+	 * it starts generating, it will first validate that you have actually specified a
+	 * resource processor for each type of artifact you provided.
+	 * 
+	 * @param output the output stream to write to
+	 * @throws Exception if something goes wrong while validating or generating
+	 */
+	public void generate(OutputStream output) throws Exception {
+		validateArtifacts();
+		List<ArtifactData> artifacts = new ArrayList<ArtifactData>();
+		artifacts.addAll(m_bundles);
+		artifacts.addAll(m_processors);
+		artifacts.addAll(m_artifacts);
+		Manifest m = createManifest(artifacts);
+		writeStream(artifacts, m, output);
+	}
+	
+	/** Returns the symbolic name of the deployment package. */
+	public String getSymbolicName() {
+		return m_symbolicName;
+	}
+
+	/** Returns the version of the deployment package. */
+	public String getVersion() {
+		return m_version;
+	}
+	
+	private DeploymentPackageBuilder addBundleArtifact(URL url, boolean isResourceProcessor) throws Exception {
+		JarInputStream jis = null;
+		try {
+			jis = new JarInputStream(url.openStream());
+	        Manifest bundleManifest = jis.getManifest();
+	        if (bundleManifest == null) {
+	        	throw new Exception("Not a valid manifest in: " + url);
+	        }
+	        Attributes attributes = bundleManifest.getMainAttributes();
+			String bundleSymbolicName = getRequiredHeader(attributes, "Bundle-SymbolicName");
+	        String bundleVersion = getRequiredHeader(attributes, "Bundle-Version");
+	        String name = PREFIX_BUNDLE + bundleSymbolicName + "-" + bundleVersion;
+	        int i = name.lastIndexOf('/');
+	        if (i > 0 && i < (name.length() - 1)) {
+	        	name = name.substring(i + 1);
+	        }
+			if (isResourceProcessor) {
+	        	if (!"true".equals(getRequiredHeader(attributes, "DeploymentPackage-Customizer"))) {
+	        		throw new IOException("Invalid DeploymentPackage-Customizer header in: " + url);
+	        	}
+	        	String processorPID = getRequiredHeader(attributes, "Deployment-ProvidesResourceProcessor");
+	        	m_processors.add(ArtifactData.createResourceProcessor(url, name, bundleSymbolicName, bundleVersion, processorPID));
+	        }
+	        else {
+	        	m_bundles.add(ArtifactData.createBundle(url, name, bundleSymbolicName, bundleVersion));
+	        }
+		}
+		finally {
+			if (jis != null) {
+				jis.close();
+			}
+		}
+		return this;
+	}
+
+	private void validateArtifacts() throws Exception {
+		for (ArtifactData data : m_artifacts) {
+			String pid = data.getProcessorPid();
+			boolean found = false;
+			for (ArtifactData processor : m_processors) {
+				if (pid.equals(processor.getProcessorPid())) {
+					found = true;
+					break;
+				}
+			}
+			if (!found) {
+				throw new Exception("No resource processor found for artifact " + data.getURL() + " with processor PID " + pid);
+			}
+		}
+	}
+	
+	private String getRequiredHeader(Attributes mainAttributes, String headerName) throws Exception {
+		String value = mainAttributes.getValue(headerName);
+		if (value == null || value.equals("")) {
+			throw new Exception("Missing or invalid " + headerName + " header.");
+		}
+		return value;
+	}
+	
+	private Manifest createManifest(List<ArtifactData> files) throws Exception {
+		Manifest manifest = new Manifest();
+        Attributes main = manifest.getMainAttributes();
+        main.putValue("Manifest-Version", "1.0");
+        main.putValue("DeploymentPackage-SymbolicName", m_symbolicName);
+        main.putValue("DeploymentPackage-Version", m_version);
+
+        for (ArtifactData file : files) {
+        	if (file.isBundle()) {
+                Attributes a = new Attributes();
+                a.putValue("Bundle-SymbolicName", file.getSymbolicName());
+                a.putValue("Bundle-Version", file.getVersion());
+                if (file.isCustomizer()) {
+                    a.putValue("DeploymentPackage-Customizer", "true");
+                    a.putValue("Deployment-ProvidesResourceProcessor", file.getProcessorPid());
+                }
+                manifest.getEntries().put(file.getFilename(), a);
+        	}
+        	else {
+                Attributes a = new Attributes();
+                a.putValue("Resource-Processor", file.getProcessorPid());
+                manifest.getEntries().put(file.getFilename(), a);
+        	}
+        }
+		return manifest;
+	}
+	
+	private void writeStream(List<ArtifactData> files, Manifest manifest, OutputStream outputStream) throws Exception {
+        JarOutputStream output = null;
+        InputStream fis = null;
+        try {
+			output = new JarOutputStream(outputStream, manifest);
+            byte[] buffer = new byte[BUFFER_SIZE];
+            for (ArtifactData file : files) {
+                output.putNextEntry(new ZipEntry(file.getFilename()));
+                fis = file.getURL().openStream();
+                int bytes = fis.read(buffer);
+                while (bytes != -1) {
+                    output.write(buffer, 0, bytes);
+                    bytes = fis.read(buffer);
+                }
+                fis.close();
+                output.closeEntry();
+                fis = null;
+            }
+        }
+        finally {
+        	if (fis != null) {
+        		fis.close();
+        	}
+            if (output != null) {
+            	output.close();
+            }
+        }
+    }
+	private synchronized int getUniqueID() {
+		return m_id++;
+	}
+}

Added: ace/sandbox/marrs/org.apache.ace.builder/test/org/apache/ace/builder/DeploymentPackageBuilderTest.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.builder/test/org/apache/ace/builder/DeploymentPackageBuilderTest.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.builder/test/org/apache/ace/builder/DeploymentPackageBuilderTest.java (added)
+++ ace/sandbox/marrs/org.apache.ace.builder/test/org/apache/ace/builder/DeploymentPackageBuilderTest.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,253 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.builder;
+
+import static org.apache.ace.test.utils.TestUtils.UNIT;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class DeploymentPackageBuilderTest {
+    @Test(groups = { UNIT })
+	public void testEmptyDeploymentPackage() throws Exception {
+		File tempFile = File.createTempFile("output-", ".jar");
+		System.out.println("File: " + tempFile);
+		FileOutputStream output = new FileOutputStream(tempFile);
+		String name = "test";
+		String version = "1.0.0";
+		DeploymentPackageBuilder.createDeploymentPackage(name, version).generate(output);
+		Manifest m = getManifest(tempFile);
+
+		// the deployment package should have just a name and a version, but no entries
+		Assert.assertEquals(name, m.getMainAttributes().getValue("DeploymentPackage-SymbolicName"));
+		Assert.assertEquals(version, m.getMainAttributes().getValue("DeploymentPackage-Version"));
+		Assert.assertTrue(m.getEntries().isEmpty());
+	}
+
+    @Test(groups = { UNIT })
+	public void testSingleBundleDeploymentPackage() throws Exception {
+		File tempFile = File.createTempFile("output-", ".jar");
+		FileOutputStream output = new FileOutputStream(tempFile);
+		String name = "test";
+		String version = "1.0.0";
+		
+		String bundleSymbolicName = "bundle";
+		String bundleVersion = "1.0.0";
+		File tempBundleFile = File.createTempFile(bundleSymbolicName + "-" + bundleVersion + "-", ".jar");
+		
+		DeploymentPackageBuilder.createDeploymentPackage(name, version)
+			.addBundle(createBundle(bundleSymbolicName, bundleVersion, tempBundleFile))
+			.generate(output);
+
+		// the deployment package should have a name and a version, and a single entry (our bundle)
+		Manifest m = getManifest(tempFile);
+		Assert.assertEquals(name, m.getMainAttributes().getValue("DeploymentPackage-SymbolicName"));
+		Assert.assertEquals(version, m.getMainAttributes().getValue("DeploymentPackage-Version"));
+		Assert.assertEquals(1, m.getEntries().size());
+		contains(m.getEntries().values(),
+			"Bundle-SymbolicName", bundleSymbolicName,
+			"Bundle-Version", bundleVersion
+		);
+	}
+
+    @Test(groups = { UNIT })
+	public void testTwoBundleDeploymentPackage() throws Exception {
+		File tempFile = File.createTempFile("output-", ".jar");
+		FileOutputStream output = new FileOutputStream(tempFile);
+		String name = "test";
+		String version = "1.0.0";
+		
+		String bundleSymbolicName = "bundle";
+		String bundleVersion = "1.0.0";
+		File tempBundleFile = File.createTempFile(bundleSymbolicName + "-" + bundleVersion + "-", ".jar");
+		
+		String bundleSymbolicName2 = "bundle-two";
+		String bundleVersion2 = "1.2.0";
+		File tempBundleFile2 = File.createTempFile(bundleSymbolicName2 + "-" + bundleVersion2 + "-", ".jar");
+
+		DeploymentPackageBuilder.createDeploymentPackage(name, version)
+			.addBundle(createBundle(bundleSymbolicName, bundleVersion, tempBundleFile))
+			.addBundle(createBundle(bundleSymbolicName2, bundleVersion2, tempBundleFile2))
+			.generate(output);
+
+		// the deployment package should have a name and a version, and a single entry (our bundle)
+		Manifest m = getManifest(tempFile);
+		Assert.assertEquals(name, m.getMainAttributes().getValue("DeploymentPackage-SymbolicName"));
+		Assert.assertEquals(version, m.getMainAttributes().getValue("DeploymentPackage-Version"));
+		Assert.assertEquals(2, m.getEntries().size());
+		contains(m.getEntries().values(),
+			"Bundle-SymbolicName", bundleSymbolicName,
+			"Bundle-Version", bundleVersion
+		);
+		contains(m.getEntries().values(),
+			"Bundle-SymbolicName", bundleSymbolicName2,
+			"Bundle-Version", bundleVersion2
+		);
+	}
+	
+    @Test(groups = { UNIT })
+	public void testProcessorAndResourceDeploymentPackage() throws Exception {
+		File tempFile = File.createTempFile("output-", ".jar");
+		FileOutputStream output = new FileOutputStream(tempFile);
+		String name = "test";
+		String version = "1.0.0";
+		
+		String bundleSymbolicName = "bundle";
+		String bundleVersion = "1.0.0";
+		File tempBundleFile = File.createTempFile(bundleSymbolicName + "-" + bundleVersion + "-", ".jar");
+		
+		String pid = "my.processor";
+
+		File tempArtifactFile = File.createTempFile("artifact-", ".jar");
+
+		DeploymentPackageBuilder.createDeploymentPackage(name, version)
+			.addResourceProcessor(createResourceProcessor(bundleSymbolicName, bundleVersion, pid, tempBundleFile))
+			.addArtifact(createArtifact(pid, tempArtifactFile), pid)
+			.generate(output);
+
+		// the deployment package should have a name and a version, and a single entry (our bundle)
+		Manifest m = getManifest(tempFile);
+		Assert.assertEquals(name, m.getMainAttributes().getValue("DeploymentPackage-SymbolicName"));
+		Assert.assertEquals(version, m.getMainAttributes().getValue("DeploymentPackage-Version"));
+		Map<String, Attributes> entries = m.getEntries();
+		Assert.assertEquals(2, entries.size());
+		contains(entries.values(),
+			"Bundle-SymbolicName", bundleSymbolicName,
+			"Bundle-Version", bundleVersion,
+			"DeploymentPackage-Customizer", "true",
+			"Deployment-ProvidesResourceProcessor", pid
+		);
+		contains(entries.values(),
+			"Resource-Processor", pid
+		);
+	}
+    
+    @Test(groups = { UNIT }, expectedExceptions = { Exception.class })
+	public void testResourceWithoutProcessorDeploymentPackage() throws Exception {
+		File tempFile = File.createTempFile("output-", ".jar");
+		FileOutputStream output = new FileOutputStream(tempFile);
+		String name = "test";
+		String version = "1.0.0";
+		
+		String pid = "my.processor";
+
+		File tempArtifactFile = File.createTempFile("artifact-", ".jar");
+
+		DeploymentPackageBuilder.createDeploymentPackage(name, version)
+			.addArtifact(createArtifact(pid, tempArtifactFile), pid)
+			.generate(output);
+	}
+	
+	
+	private Manifest getManifest(File file) throws Exception {
+        JarInputStream jis = new JarInputStream(file.toURI().toURL().openStream());
+        Manifest bundleManifest = jis.getManifest();
+        jis.close();
+        return bundleManifest;
+	}
+	
+	private URL createBundle(String symbolicName, String version, File file) throws Exception {
+		Manifest manifest = new Manifest();
+        Attributes main = manifest.getMainAttributes();
+        main.putValue("Manifest-Version", "1.0");
+        main.putValue("Bundle-SymbolicName", symbolicName);
+        main.putValue("Bundle-Version", version);
+        
+        JarOutputStream output = null;
+        InputStream fis = null;
+        try {
+			output = new JarOutputStream(new FileOutputStream(file), manifest);
+			return file.toURI().toURL();
+        }
+        finally {
+            if (output != null) {
+            	output.close();
+            }
+            if (fis != null) {
+                fis.close();
+            }
+        }
+	}
+	
+	private URL createResourceProcessor(String symbolicName, String version, String processorPID, File file) throws Exception {
+		Manifest manifest = new Manifest();
+        Attributes main = manifest.getMainAttributes();
+        main.putValue("Manifest-Version", "1.0");
+        main.putValue("Bundle-SymbolicName", symbolicName);
+        main.putValue("Bundle-Version", version);
+        main.putValue("DeploymentPackage-Customizer", "true");
+        main.putValue("Deployment-ProvidesResourceProcessor", processorPID);
+        
+        JarOutputStream output = null;
+        InputStream fis = null;
+        try {
+			output = new JarOutputStream(new FileOutputStream(file), manifest);
+			return file.toURI().toURL();
+        }
+        finally {
+            if (output != null) {
+            	output.close();
+            }
+            if (fis != null) {
+                fis.close();
+            }
+        }
+	}
+
+	private URL createArtifact(String processorPID, File file) throws Exception {
+        FileOutputStream output = null;
+        try {
+			output = new FileOutputStream(file);
+			output.write(0);
+			return file.toURI().toURL();
+        }
+        finally {
+            if (output != null) {
+            	output.close();
+            }
+        }
+	}
+
+	private void contains(Collection<Attributes> list, String... keysAndValues) {
+		for (Attributes attributes : list) {
+			boolean found = true;
+			for (int i = 0; i < keysAndValues.length; i += 2) {
+				if (!keysAndValues[i + 1].equals(attributes.getValue(keysAndValues[i]))) {
+					found = false;
+					break;
+				}
+			}
+			if (found) {
+				return;
+			}
+		}
+		throw new IllegalStateException("Could not find entry in list.");
+	}
+}

Added: ace/sandbox/marrs/org.apache.ace.client.automation/.classpath
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.automation/.classpath?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.automation/.classpath (added)
+++ ace/sandbox/marrs/org.apache.ace.client.automation/.classpath Thu Jul  5 12:09:30 2012
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="aQute.bnd.classpath.container"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

Added: ace/sandbox/marrs/org.apache.ace.client.automation/.project
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.automation/.project?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.automation/.project (added)
+++ ace/sandbox/marrs/org.apache.ace.client.automation/.project Thu Jul  5 12:09:30 2012
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.apache.ace.client.automation</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>bndtools.core.bndbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>bndtools.core.bndnature</nature>
+	</natures>
+</projectDescription>

Added: ace/sandbox/marrs/org.apache.ace.client.automation/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.automation/bnd.bnd?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.automation/bnd.bnd (added)
+++ ace/sandbox/marrs/org.apache.ace.client.automation/bnd.bnd Thu Jul  5 12:09:30 2012
@@ -0,0 +1,7 @@
+-buildpath: osgi.core,\
+	osgi.cmpn,\
+	org.apache.felix.dependencymanager,\
+	org.apache.ace.scheduler.api;version=latest,\
+	org.apache.ace.client.repository.api;version=latest
+Private-Package: org.apache.ace.client.automation
+Bundle-Activator: org.apache.ace.client.automation.Activator
\ No newline at end of file

Added: ace/sandbox/marrs/org.apache.ace.client.automation/build.xml
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.automation/build.xml?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.automation/build.xml (added)
+++ ace/sandbox/marrs/org.apache.ace.client.automation/build.xml Thu Jul  5 12:09:30 2012
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="project" default="build"> 
+	<import file="../cnf/build.xml"/>
+</project>

Added: ace/sandbox/marrs/org.apache.ace.client.automation/pom.xml
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.automation/pom.xml?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.automation/pom.xml (added)
+++ ace/sandbox/marrs/org.apache.ace.client.automation/pom.xml Thu Jul  5 12:09:30 2012
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ace</groupId>
+        <artifactId>ace-pom</artifactId>
+        <version>0.8.1-SNAPSHOT</version>
+        <relativePath>../pom/pom.xml</relativePath>
+    </parent>
+
+    <version>0.8.1-SNAPSHOT</version>
+    <artifactId>org.apache.ace.client.automation</artifactId>
+    <packaging>bundle</packaging>
+
+    <name>Apache ACE :: Client :: Automation</name>
+    <description>Client bundle that automatically registers new targets that connect with the server, approves outgoing changes and turns on automatic approval of future updates.</description>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/ace/trunk/ace-client-automation</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/ace/trunk/ace-client-automation</developerConnection>
+        <url>http://svn.apache.org/repos/asf/ace/trunk/ace-client-automation</url>
+    </scm>
+
+    <properties>
+        <bundle.activator>org.apache.ace.client.automation.Activator</bundle.activator>
+        <import.package>
+            org.apache.ace.client.repository;version=${project.version},
+            org.apache.ace.client.repository.repository;version=${project.version},
+            org.apache.ace.client.repository.stateful;version=${project.version},
+            *
+        </import.package>
+        <private.package>
+            org.apache.ace.client.automation
+        </private.package>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.client.repository.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.scheduler.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

Added: ace/sandbox/marrs/org.apache.ace.client.automation/src/org/apache/ace/client/automation/Activator.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.automation/src/org/apache/ace/client/automation/Activator.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.automation/src/org/apache/ace/client/automation/Activator.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.automation/src/org/apache/ace/client/automation/Activator.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.automation;
+
+import org.apache.ace.client.repository.RepositoryAdmin;
+import org.apache.ace.client.repository.repository.DeploymentVersionRepository;
+import org.apache.ace.client.repository.repository.TargetRepository;
+import org.apache.ace.client.repository.stateful.StatefulTargetRepository;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Bundle activator for the target operator automation.
+ */
+public class Activator extends DependencyActivatorBase {
+    /**
+     * Initialize and set dependencies
+     */
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        manager.add(createComponent()
+            .setImplementation(AutoTargetOperator.class)
+            .add(createConfigurationDependency().setPid(AutoTargetOperator.PID))
+            .add(createServiceDependency().setRequired(true).setService(UserAdmin.class))
+            .add(createServiceDependency().setRequired(true).setService(TargetRepository.class)) // TODO is this still used?
+            .add(createServiceDependency().setRequired(true).setService(StatefulTargetRepository.class))
+            .add(createServiceDependency().setRequired(true).setService(DeploymentVersionRepository.class))
+            .add(createServiceDependency().setRequired(true).setService(RepositoryAdmin.class))
+            .add(createServiceDependency().setRequired(false).setService(LogService.class))
+        );
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+    }
+}
\ No newline at end of file

Added: ace/sandbox/marrs/org.apache.ace.client.automation/src/org/apache/ace/client/automation/AutoTargetOperator.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.automation/src/org/apache/ace/client/automation/AutoTargetOperator.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.automation/src/org/apache/ace/client/automation/AutoTargetOperator.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.automation/src/org/apache/ace/client/automation/AutoTargetOperator.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.automation;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Properties;
+import org.apache.ace.client.repository.RepositoryAdmin;
+import org.apache.ace.client.repository.RepositoryAdminLoginContext;
+import org.apache.ace.client.repository.object.TargetObject;
+import org.apache.ace.client.repository.stateful.StatefulTargetObject;
+import org.apache.ace.client.repository.stateful.StatefulTargetRepository;
+import org.apache.ace.scheduler.constants.SchedulerConstants;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+/**
+ * Automatic target operator, when configured will automatically register, approve, auto-approve
+ * and commit targets to the repository. An LDAP filter can be used to filter for the correct targets.
+ */
+public class AutoTargetOperator implements ManagedService {
+
+    public static final String PID = "org.apache.ace.client.automation";
+    public static final String SCHEDULER_NAME = "org.apache.ace.client.processauditlog";
+
+    private volatile StatefulTargetRepository m_statefulTargetRepos;
+    private volatile RepositoryAdmin m_reposAdmin;
+    private volatile UserAdmin m_userAdmin;
+    private volatile BundleContext m_bundleContext;
+    private volatile LogService m_log;
+    @SuppressWarnings("unchecked")
+    private volatile Dictionary m_settings;
+
+    private static String username = "serverUser";
+
+    // used for processing the auditlog (tell the repository about that)
+    private final AuditLogProcessTask m_task = new AuditLogProcessTask();
+    private Object m_serviceReg = null;
+
+    public void start() {
+        // get user
+        User user = m_userAdmin.getUser("username",username);
+
+        // login at Repository admin
+        try {
+            URL url =  new URL(getConfigValue( ConfigItem.HOSTNAME) + getConfigValue( ConfigItem.ENDPOINT));
+            String customerName = getConfigValue( ConfigItem.CUSTOMER_NAME);
+
+            RepositoryAdminLoginContext loginContext = m_reposAdmin.createLoginContext(user);
+            loginContext
+                .add(loginContext.createShopRepositoryContext()
+                    .setLocation(url).setCustomer(customerName).setName(getConfigValue(ConfigItem.STORE_REPOSITORY)))
+                .add(loginContext.createTargetRepositoryContext()
+                    .setLocation(url).setCustomer(customerName).setName(getConfigValue(ConfigItem.TARGET_REPOSITORY)).setWriteable())
+                .add(loginContext.createDeploymentRepositoryContext()
+                    .setLocation(url).setCustomer(customerName).setName(getConfigValue(ConfigItem.DEPLOYMENT_REPOSITORY)).setWriteable());
+
+            m_reposAdmin.login(loginContext);
+
+            // start refresh task
+            Properties props = new Properties();
+            props.put(SchedulerConstants.SCHEDULER_NAME_KEY, SCHEDULER_NAME);
+            m_serviceReg = m_bundleContext.registerService(Runnable.class.getName(), m_task, props);
+        }
+        catch (IOException ioe) {
+            m_log.log(LogService.LOG_ERROR, "Unable to login at repository admin.", ioe);
+        }
+    }
+
+    public void stop() {
+        // service present, pull it
+        if (m_serviceReg != null) {
+            ((ServiceRegistration) m_serviceReg).unregister();
+        }
+
+        m_serviceReg = null;
+
+        //logout
+        try {
+            m_reposAdmin.logout(true);
+        }
+        catch (IOException ioe) {
+            // not a lot we can
+            System.err.println(ioe.getMessage());
+        }
+    }
+
+    /**
+     * Runnable that will synchronize audit log data with the server and tell the repository about the changes if applicable.
+     */
+    private final class AuditLogProcessTask implements Runnable {
+
+        private final Object m_lock = new Object();
+
+        public void process() {
+            // perform synchronous model actions
+            synchronized(m_lock) {
+                m_statefulTargetRepos.refresh();
+                boolean changed = false;
+                try {
+                    checkoutModel();
+                    changed |= registerTargets();
+                    changed |= approveTargets();
+                    changed |= setAutoApprove();
+                }
+                catch (IOException ioe) {
+                    m_log.log(LogService.LOG_WARNING, "Checkout of model failed.", ioe);
+                }
+                catch (InvalidSyntaxException ise) {
+                    m_log.log(LogService.LOG_WARNING, "Illegal register target filter.", ise);
+                }
+
+                // Commit any changes
+                try {
+                    if (changed) {
+                        m_reposAdmin.commit();
+                    }
+                }
+                catch (IOException ioe) {
+                    m_log.log(LogService.LOG_WARNING, "Commit of model failed", ioe);
+                }
+            }
+        }
+
+        public void run() {
+                process();
+        }
+    }
+
+    private void checkoutModel() throws IOException {
+        // Do a checkout
+        if (!m_reposAdmin.isCurrent()) {
+               m_reposAdmin.checkout();
+        }
+    }
+
+    private boolean registerTargets() throws InvalidSyntaxException {
+        boolean changed = false;
+        String filter = "(&" + getConfigValue( ConfigItem.REGISTER_TARGET_FILTER) +
+        "(" + StatefulTargetObject.KEY_REGISTRATION_STATE + "=" + StatefulTargetObject.RegistrationState.Unregistered + "))";
+        List<StatefulTargetObject> stos =  m_statefulTargetRepos.get(m_bundleContext.createFilter(filter));
+        for (StatefulTargetObject sto : stos) {
+            sto.register();
+            changed = true;
+        }
+        return changed;
+    }
+
+    private boolean setAutoApprove() throws InvalidSyntaxException {
+        boolean changed = false;
+        String filter = "(&" + getConfigValue( ConfigItem.AUTO_APPROVE_TARGET_FILTER) +
+        "(" + StatefulTargetObject.KEY_REGISTRATION_STATE + "=" + StatefulTargetObject.RegistrationState.Registered + ")" +
+        "(!(" + TargetObject.KEY_AUTO_APPROVE + "=true)))";
+
+        List<StatefulTargetObject> stos =  m_statefulTargetRepos.get(m_bundleContext.createFilter(filter));
+        for (StatefulTargetObject sto : stos) {
+                sto.setAutoApprove(true);
+                changed = true;
+            }
+        return changed;
+    }
+
+    private boolean approveTargets() throws InvalidSyntaxException {
+        boolean changed = false;
+        String filter = "(&" + getConfigValue( ConfigItem.APPROVE_TARGET_FILTER) +
+        "(" + StatefulTargetObject.KEY_STORE_STATE + "=" + StatefulTargetObject.StoreState.Unapproved + "))";
+
+        List<StatefulTargetObject> stos =  m_statefulTargetRepos.get(m_bundleContext.createFilter(filter));
+            for (StatefulTargetObject sto : stos) {
+                sto.approve();
+                changed = true;
+            }
+        return changed;
+    }
+
+    @SuppressWarnings("unchecked")
+    public void updated(Dictionary settings) throws ConfigurationException {
+        if (settings != null) {
+            for (ConfigItem item : ConfigItem.values()) {
+                String value = (String) settings.get(item.toString());
+                if ((value == null) || value.equals("")) {
+                    throw new ConfigurationException(item.toString(), item.getErrorText());
+                }
+            }
+            // store configuration
+            m_settings = settings;
+        }
+    }
+
+    /**
+     * @param item The configuration item (enum)
+     * @return The value stored in the configuration dictionary.
+     */
+    private String getConfigValue(ConfigItem item) {
+        return (String) m_settings.get(item.toString());
+    }
+
+    /**
+     *  Helper class used for target automation client configuration.
+     *  ENUM (itemname, errormessage, filter true/false)
+     *
+     */
+    private enum ConfigItem {
+        REGISTER_TARGET_FILTER ("registerTargetFilter", "Register target filter missing", true),
+        APPROVE_TARGET_FILTER ("approveTargetFilter", "Approve target filter missing", true),
+        AUTO_APPROVE_TARGET_FILTER ("autoApproveTargetFilter", "Auto approve config value missing", true),
+        COMMIT_REPO ("commitRepositories", "Commit value missing.", false),
+        TARGET_REPOSITORY ("targetRepository", "TargetRepository id missing.", false),
+        DEPLOYMENT_REPOSITORY ("deploymentRepository", "DeploymentRepository id missing.", false),
+        STORE_REPOSITORY ("storeRepository", "Store Repository id missing.", false),
+        CUSTOMER_NAME ("customerName", "Customer name missing", false),
+        HOSTNAME ("hostName", "Hostname missing.", false),
+        ENDPOINT ("endpoint", "Endpoint missing in config.", false);
+
+        private final String m_name;
+        private final String m_errorText;
+        private final boolean m_isFilter;
+
+        private ConfigItem(String name, String errorText, boolean isFilter) {
+            m_name = name;
+            m_errorText = errorText;
+            m_isFilter = isFilter;
+        }
+
+        @Override
+        public String toString() {
+            return m_name;
+        }
+
+        public String getErrorText() {
+            return m_errorText;
+        }
+
+        public boolean isFilter() {
+            return m_isFilter;
+        }
+    }
+}
\ No newline at end of file

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/.classpath
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/.classpath?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/.classpath (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/.classpath Thu Jul  5 12:09:30 2012
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="aQute.bnd.classpath.container"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/.project
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/.project?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/.project (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/.project Thu Jul  5 12:09:30 2012
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.apache.ace.client.repository.api</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>bndtools.core.bndbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>bndtools.core.bndnature</nature>
+	</natures>
+</projectDescription>

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/bnd.bnd?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/bnd.bnd (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/bnd.bnd Thu Jul  5 12:09:30 2012
@@ -0,0 +1,10 @@
+-buildpath: org.apache.ace.deployment.provider.api;version=latest,\
+	osgi.core,\
+	osgi.cmpn,\
+	org.apache.ace.log;version=latest
+Export-Package: org.apache.ace.client.repository,\
+	org.apache.ace.client.repository.helper,\
+	org.apache.ace.client.repository.helper.bundle,\
+	org.apache.ace.client.repository.object,\
+	org.apache.ace.client.repository.repository,\
+	org.apache.ace.client.repository.stateful
\ No newline at end of file

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/build.xml
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/build.xml?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/build.xml (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/build.xml Thu Jul  5 12:09:30 2012
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="project" default="build"> 
+	<import file="../cnf/build.xml"/>
+</project>

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/pom.xml
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/pom.xml?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/pom.xml (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/pom.xml Thu Jul  5 12:09:30 2012
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ace</groupId>
+        <artifactId>ace-pom</artifactId>
+        <version>0.8.1-SNAPSHOT</version>
+        <relativePath>../pom/pom.xml</relativePath>
+    </parent>
+
+    <version>0.8.1-SNAPSHOT</version>
+    <artifactId>org.apache.ace.client.repository.api</artifactId>
+    <packaging>bundle</packaging>
+
+    <name>Apache ACE :: Client :: Repository :: API</name>
+    <description>Client API for working with Apache ACE from code, a script or a UI.</description>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/ace/trunk/ace-client-repository-api</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/ace/trunk/ace-client-repository-api</developerConnection>
+        <url>http://svn.apache.org/repos/asf/ace/trunk/ace-client-repository-api</url>
+    </scm>
+
+    <properties>
+        <export.package>
+            org.apache.ace.client.repository;version=${project.version},
+            org.apache.ace.client.repository.helper;version=${project.version},
+            org.apache.ace.client.repository.helper.bundle;version=${project.version},
+            org.apache.ace.client.repository.object;version=${project.version},
+            org.apache.ace.client.repository.repository;version=${project.version},
+            org.apache.ace.client.repository.stateful;version=${project.version}
+        </export.package>
+        <import.package>
+            !org.apache.ace.client.repository,
+            !org.apache.ace.client.repository.helper,
+            !org.apache.ace.client.repository.helper.bundle,
+            !org.apache.ace.client.repository.object,
+            !org.apache.ace.client.repository.repository,
+            !org.apache.ace.client.repository.stateful,
+            org.apache.ace.log;version=${project.version},
+            *
+        </import.package>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.log</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.deployment.provider.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/Associatable.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/Associatable.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/Associatable.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/Associatable.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository;
+
+import java.util.List;
+
+/**
+ * The Associatable interface is to be implemented by any object that wants to be
+ * used in an Association.
+ */
+public interface Associatable
+{
+    /**
+     * Adds the association to this object, which has the given class. The 'other side' of
+     * the association will now show up when filtering for <code>clazz</code>, which is the
+     * class of the other end of the association.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends Associatable> void add(Association association, Class<T> clazz);
+    /**
+     * Removes the association from this object, with the given class. The 'other side' of
+     * the association will no longer show up when filtering for <code>clazz</code>.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends Associatable> void remove(Association association, Class<T> clazz);
+    /**
+     * Gets all Associatable objects of the <code>clazz</code> with which this object
+     * is associated. If <code>clazz</code> is not in use, this function will return
+     * an empty list.
+     */
+    public <T extends Associatable> List<T> getAssociations(Class<T> clazz);
+    /**
+     * Checks whether this object is related with <code>obj</code>, which is to be of class
+     * <code>clazz</code>. Will also return <code>false</code> when the class does not match.
+     */
+    public <T extends Associatable> boolean isAssociated(Object obj, Class<T> clazz);
+    /**
+     * Returns the associations that exist between this object and the other, of the
+     * given <code>clazz</code>, in a typed list of associations <code>associationType</code>.
+     * Will return an empty list if no associations exist.
+     */
+    @SuppressWarnings("unchecked")
+    public <T extends Associatable, A extends Association> List<A> getAssociationsWith(Associatable other, Class<T> clazz, Class<A> associationType);
+}
\ No newline at end of file

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/Association.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/Association.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/Association.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/Association.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository;
+
+import java.util.List;
+
+/**
+ * Represents a basic association between two Associatable objects, whose types
+ * are given by the generic parameters.
+ */
+public interface Association<L extends Associatable, R extends Associatable> extends RepositoryObject {
+    /**
+     * A filter string indicating the left endpoint.
+     */
+    public final static String LEFT_ENDPOINT = "leftEndpoint";
+    /**
+     * A filter string indicating the right endpoint.
+     */
+    public final static String RIGHT_ENDPOINT = "rightEndpoint";
+    /**
+     * A string indicating the cardinality for the left endpoint.
+     */
+    public final static String LEFT_CARDINALITY = "leftCardinality";
+    /**
+     * A string indicating the cardinality for the right endpoint.
+     */
+    public final static String RIGHT_CARDINALITY = "rightCardinality";
+
+    /**
+     * Used for <code>Event</code> properties: A <code>List&lt;Associatable&gt;</code> indicating the
+     * objects making up this endpoint before the event happened.
+     */
+    public final static String EVENT_OLD = "old";
+    /**
+     * Used for <code>Event</code> properties: A <code>List&lt;Associatable&gt;</code> indicating the
+     * objects making up this endpoint before the event happened.
+     */
+    public final static String EVENT_NEW = "new";
+
+    /**
+     * Gets the Associatable object on the 'other side' of <code>from</code>. If
+     * <code>from</code> does not point to either end of this association, this
+     * function will return <code>null</code>.
+     */
+    public List<Associatable> getTo(Associatable from);
+    /**
+     * Returns the 'left' side of this association.
+     */
+    public List<L> getLeft();
+    /**
+     * Returns the 'left' side of this association.
+     */
+    public List<R> getRight();
+    /**
+     * Removes this association from both endpoints.
+     */
+    public void remove();
+    /**
+     * Indicates whether both sides of this association are available. In an m-to-n assocation,
+     * this function will indicate whether at least one object is available on either side.
+     */
+    public boolean isSatisfied();
+}
\ No newline at end of file

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/AssociationRepository.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/AssociationRepository.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/AssociationRepository.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/AssociationRepository.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a basic repository of associations. The associations are to be of type
+ * <code>T</code>, associating types <code>L</code> and <code>R</code>.
+ */
+public interface AssociationRepository<L extends Associatable, R extends Associatable, T extends Association<L, R>> extends ObjectRepository<T>{
+    /**
+     * Creates a static association between two filters for objects, stores it,
+     * and returns the association object. This association will link all objects
+     * that apply to the filters in an m-to-n fashion.
+     */
+    public T create(String left, String right);
+    /**
+     * Creates a static association between two objects, stores it,
+     * and returns the association object.
+     */
+    public T create(L left, R right);
+    /**
+     * Creates an association between the given objects, with the <code>Props</code> containing
+     * additional directives for the endpoints, stores it, and returns the association.
+     */
+    public T create(L left, Map<String, String> leftProps, R right, Map<String, String> rightProps);
+    /**
+     * Creates a static association between two lists of objects, stores it,
+     * and returns the association object.
+     */
+    public T create(List<L> left, List<R> right);
+    /**
+     * Removes the given association, and deletes the association from the left- and right
+     * side of the association.
+     */
+    public void remove(T entity);
+}
\ No newline at end of file

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/ObjectRepository.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/ObjectRepository.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/ObjectRepository.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/ObjectRepository.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository;
+
+import java.util.List;
+import java.util.Map;
+import org.osgi.framework.Filter;
+
+/**
+ * A basic object repository, storing implementers of RepositoryObject.
+ */
+public interface ObjectRepository<T extends RepositoryObject> {
+    /**
+     * Removes the given entity from this repository. Will silently fail
+     * when the entity does not exist in this repository.
+     */
+    public void remove(T entity);
+    /**
+     * Gets a list of all entities in this repository.
+     */
+    public List<T> get();
+    /**
+     * Returns a list of all entities in this repository that satisfy
+     * the conditions set in <code>filter</code>. If none match, an
+     * empty list will be returned.
+     */
+    public List<T> get(Filter filter);
+    /**
+     * Returns the entity in this repository that has the given definition.
+     * If none match, null will return. 
+     * 
+     * @param definition the definition of the entity to be returned
+     * @return The entity in this repository that has the given definition or <code>null</code> if none.
+     */
+    public T get(String definition);
+
+    /**
+     * Creates a new inhabitant based on the given attributes. The object
+     * will be stored in this repository's store, and will be returned.
+     * @throws IllegalArgumentException Will be thrown when the attributes cannot be accepted.
+     */
+    public T create(Map<String, String> attributes, Map<String, String> tags) throws IllegalArgumentException;
+}
\ No newline at end of file

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryAdmin.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryAdmin.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryAdmin.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryAdmin.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository;
+
+import java.io.IOException;
+import org.apache.ace.client.repository.RepositoryObject.WorkingState;
+import org.osgi.service.useradmin.User;
+
+public interface RepositoryAdmin
+{
+
+    public static final String PUBLIC_TOPIC_ROOT = RepositoryAdmin.class.getPackage().getName().replace('.', '/') + "/public/";
+    public static final String PRIVATE_TOPIC_ROOT = RepositoryAdmin.class.getPackage().getName().replace('.', '/') + "/private/";
+
+    public static final String TOPIC_ENTITY_ROOT = RepositoryAdmin.class.getSimpleName() + "/";
+
+    public static final String TOPIC_REFRESH_SUFFIX = "REFRESH";
+    public static final String TOPIC_LOGIN_SUFFIX = "LOGIN";
+    public static final String TOPIC_LOGOUT_SUFFIX = "LOGOUT";
+    public static final String TOPIC_STATUSCHANGED_SUFFIX = "STATUSCHANGED";
+    public static final String TOPIC_FLUSHED_SUFFIX = "FLUSHED";
+    public static final String TOPIC_ALL_SUFFIX = "*";
+
+    /**
+     * Indicates a serious change to the structure of the repository, which is too complicated to use
+     * the Object's own Changed topic.
+     */
+    public static final String TOPIC_REFRESH = PUBLIC_TOPIC_ROOT + TOPIC_ENTITY_ROOT + TOPIC_REFRESH_SUFFIX;
+    /**
+     * Indicates a successful login; the model will now be filled, as signaled by the earlier TOPIC_REFRESH.
+     */
+    public static final String TOPIC_LOGIN = PUBLIC_TOPIC_ROOT + TOPIC_ENTITY_ROOT + TOPIC_LOGIN_SUFFIX;
+    /**
+     * Indicates a successful logout; the model will now be empty, as signaled by the earlier TOPIC_REFRESH.
+     */
+    public static final String TOPIC_LOGOUT = PUBLIC_TOPIC_ROOT + TOPIC_ENTITY_ROOT + TOPIC_LOGOUT_SUFFIX;
+    /**
+     * Signals that isCurrent or isModified have (potentially) changed.
+     */
+    public static final String TOPIC_STATUSCHANGED = PUBLIC_TOPIC_ROOT + TOPIC_ENTITY_ROOT + TOPIC_STATUSCHANGED_SUFFIX;
+    /**
+     * Signals that a flush() has been done.
+     */
+    public static final String TOPIC_FLUSHED = PUBLIC_TOPIC_ROOT + TOPIC_ENTITY_ROOT + TOPIC_FLUSHED_SUFFIX;
+
+    public static final String TOPIC_ALL = PUBLIC_TOPIC_ROOT + TOPIC_ENTITY_ROOT + TOPIC_ALL_SUFFIX;
+
+    /**
+     * Checks out the most recent version of the repositories from <code>login</code>.
+     * @throws java.io.IOException Thrown when we are not logged in, or when there is a problem
+     * communicating with either the local repository or the remote one.
+     */
+    public void checkout() throws IOException;
+
+    /**
+     * Commits the most what we have in memory to the repositories from <code>login</code>.
+     * @throws java.io.IOException Thrown when we are not logged in, or when there is a problem
+     * communicating with either the local repository or the remote one.
+     */
+    public void commit() throws IOException;
+
+    /**
+     * Reverts what we have in memory to the most recent one that was checked our or
+     * committed.
+     * @throws java.io.IOException Thrown when we are not logged in, or when there is a problem
+     * communicating with either the local repository or the remote one.
+     */
+    public void revert() throws IOException;
+
+    /**
+     * Indicates that the version on which the changes are made is the most recent on the server.
+     * This indication only applies to repositories for which write access has been received.
+     * @throws java.io.IOException Thrown when there is a problem communicating with the backup repository,
+     * which keeps track of the local copies of the repository.
+     */
+    public boolean isCurrent() throws IOException;
+
+    /**
+     * Indicates whether the data we have (in memory and persisted) has changed in respect to
+     * what is on the server.
+     * @throws java.io.IOException Thrown when there is a problem communicating with the backup repository,
+     * which keeps track of the local copies of the repository.
+     */
+    public boolean isModified() throws IOException;
+
+    /**
+     * Writes what we have in memory to a backup repository, so it can be persisted between runs
+     * of the client, without committing it to the remote repository.
+     * @throws java.io.IOException Thrown when there is a problem communicating with the backup repository,
+     * which keeps track of the local copies of the repository.
+     */
+    public void flush() throws IOException;
+
+    /**
+     * Writes what we have in memory to a backup repository, and prepares the repository for use by
+     * a new user.
+     * @param force Indicates that, even when an exception is thrown, we still want to log the
+     * user out.
+     * @throws java.io.IOException Thrown when there is a problem communicating with the backup repository,
+     * which keeps track of the local copies of the repository. If this exception is thrown,
+     * the user is still logged in, unless <code>force = true</code>.
+     * @throws IllegalStateException Thrown if no user is logged in.
+     */
+    public void logout(boolean force) throws IOException, IllegalStateException;
+
+    /**
+     * Creates a new login context.
+     * @param user The user to use for this context.
+     * @return A new RepositoryAdminLoginContext,
+     */
+    public RepositoryAdminLoginContext createLoginContext(User user);
+
+    /**
+     * Logs in using the given RepositoryAdminLoginContext; use createLoginContext for an initial
+     * RepositoryAdminLoginContext.
+     * @param context The context to use for this login.
+     * @throws java.io.IOException Thrown when there is a problem communicating with the backup repository,
+     * which keeps track of the local copies of the repository.
+     * @throws IllegalArgumentException If <code>context</code> was not one that was
+     * created by <code>createLoginContext</code<.
+     * @throws IllegalStateException If there already is a user logged in.
+     */
+    public void login(RepositoryAdminLoginContext context) throws IOException;
+
+    /**
+     * Return the working state of the given object. If the object is not part of any
+     * repository managed by this admin, <code>New</code> will be returned.
+     * @param object A repository object.
+     * @return The current working state of this object.
+     */
+    public WorkingState getWorkingState(RepositoryObject object);
+
+    /**
+     * Gets the number of objects of a given class with a given state. Note that
+     * this class applies to all objects of that class, and all its descendents.
+     * @param clazz The class of objects to be counted.
+     * @param state A working state.
+     * @return The number of objects which are (or descend from) the given class,
+     * and have the given working state.
+     */
+    public int getNumberWithWorkingState(Class<? extends RepositoryObject> clazz, WorkingState state);
+}
\ No newline at end of file

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryAdminLoginContext.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryAdminLoginContext.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryAdminLoginContext.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryAdminLoginContext.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository;
+
+import java.net.URL;
+
+/**
+ * RepositoryAdminLoginContext represents a context for logins to the repository admin. It is used to specify
+ * which repositories are to be used in a given session with the RepositoryAdmin.
+ */
+public interface RepositoryAdminLoginContext
+{
+    /**
+     * Provides a common interface for all repository contexts.
+     * 
+     * @param <T> the actual context type to return in this builder.
+     */
+    public interface BaseRepositoryContext<T extends BaseRepositoryContext<?>> {
+    
+        /**
+         * @param location the location of the repository where this set's data resides.
+         * @return this context.
+         */
+        T setLocation(URL location);
+    
+        /**
+         * @param customer the customer name for the location of the repository where this set's data resides.
+         * @return this context.
+         */
+        T setCustomer(String customer);
+    
+        /**
+         * @param name the repository name for the location of the repository where this set's data resides.
+         * @return this context.
+         */
+        T setName(String name);
+    
+        /**
+         * Marks this repository as writable (default is read-only).
+         * 
+         * @return this context.
+         */
+        T setWriteable();
+    }
+
+    /**
+     * Denotes a context for creating shop repositories.
+     */
+    public static interface ShopRepositoryContext extends BaseRepositoryContext<ShopRepositoryContext> {
+    }
+
+    /**
+     * Denotes a context for creating target repositories.
+     */
+    public static interface TargetRepositoryContext extends BaseRepositoryContext<TargetRepositoryContext> {
+    }
+
+    /**
+     * Denotes a context for creating deployment repositories.
+     */
+    public static interface DeploymentRepositoryContext extends BaseRepositoryContext<DeploymentRepositoryContext> {
+    }
+
+    /**
+     * @return a new shop repository context, never <code>null</code>.
+     */
+    public ShopRepositoryContext createShopRepositoryContext();
+
+    /**
+     * @return a new target repository context, never <code>null</code>.
+     */
+    public TargetRepositoryContext createTargetRepositoryContext();
+
+    /**
+     * @return a new deployment repository context, never <code>null</code>.
+     */
+    public DeploymentRepositoryContext createDeploymentRepositoryContext();
+
+    /**
+     * @param repositoryContext the context to add, cannot be <code>null</code>.
+     * @return this context, never <code>null</code>.
+     */
+    public RepositoryAdminLoginContext add(BaseRepositoryContext<?> repositoryContext);
+
+    /**
+     * When uploads are needed, this is the base OBR that will be used.
+     * 
+     * @param base The URL of the OBR to be used.
+     * @return this object, to allow chaining.
+     */
+    public RepositoryAdminLoginContext setObrBase(URL base);
+}

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryObject.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryObject.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryObject.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryObject.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository;
+
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Map;
+
+/**
+ * A basic repository object, intended to be stored in a ObjectRepository of its given type.
+ * A RepositoryObject is associatable.
+ */
+public interface RepositoryObject extends Associatable {
+    /**
+     * This key is used to store the RepositoryObject an event comes from, in the Event object.
+     */
+    public final static String EVENT_ENTITY = "entity";
+
+    public static final String PUBLIC_TOPIC_ROOT = RepositoryObject.class.getPackage().getName().replace('.', '/') + "/public/";
+    public static final String PRIVATE_TOPIC_ROOT = RepositoryObject.class.getPackage().getName().replace('.', '/') + "/private/";
+
+    public static final String TOPIC_ADDED_SUFFIX = "ADDED";
+    public static final String TOPIC_REMOVED_SUFFIX = "REMOVED";
+    public static final String TOPIC_CHANGED_SUFFIX = "CHANGED";
+    public static final String TOPIC_ALL_SUFFIX = "*";
+
+    /**
+     * Adds a named attribute to this object's attributes. If the name already exists,
+     * it will be overwritten, and the old value is returned; will return <code>null</code>
+     * when the value is new.
+     */
+    public String addAttribute(String key, String value);
+    /**
+     * Gets a named attribute. Returns <code>null<code> when the attribute named by
+     * <code>key</code> does not exist.
+     */
+    public String getAttribute(String key);
+    /**
+     * Returns an enumeration of all attribute keys.
+     */
+    public Enumeration<String> getAttributeKeys();
+    /**
+     * Adds a named tag to this object's attributes. If the name already exists,
+     * it will be overwritten, and the old value is returned; will return <code>null</code>
+     * when the value is new.
+     */
+    public String addTag(String key, String value);
+    /**
+     * Gets a named tag. Returns <code>null<code> when the attribute named by
+     * <code>key</code> does not exist.
+     */
+    public String getTag(String key);
+    /**
+     * Returns an enumeration of all tags in this object, coming from both the
+     * tags and the attributes.
+     */
+    public Enumeration<String> getTagKeys();
+    /**
+     * Returns a <code>Dictionary</code> representing this object. It will contain all keys,
+     * from <code>getTagKeys</code>, and all values that correspond to them. If a key is present
+     * in both the attributes and the tags, the corresponding value will be an array of two
+     * <code>String</code> objects; otherwise a single <code>String</code> is returned.
+     */
+    public Dictionary<String, Object> getDictionary();
+    /**
+     * Indicates that this object should no longer be used.
+     */
+    public boolean isDeleted();
+    /**
+     * Creates a filter string for use in associations, optionally with some
+     * additional properties. The basic implementation will use all <code>getDefiningKeys</code>.
+     * @param properties Properties indicating specifics of the filter to be created.
+     * @return A string representation of a filter, for use in <code>Association</code>s.
+     */
+    public String getAssociationFilter(Map<String, String> properties);
+
+    /**
+     * Determines the cardinality of this endpoint of an association, given
+     * the passed properties.
+     * @param properties Properties indicating specifics of this endpoint.
+     * @return The necessary cardinality.
+     */
+    public int getCardinality(Map<String, String> properties);
+
+    /**
+     * Returns a <code>Comparator</code> for this type of object. Descendent
+     * classes are expected to return a comparator if they can be meaningfully compared,
+     * and otherwise (if no order is natural), return <code>null</code>.
+     * @return A <code>Comparator</code> for this type of object
+     */
+    @SuppressWarnings("unchecked")
+    public Comparator getComparator();
+
+    /**
+     * Returns a string which uniquely defines this object. The content is
+     * not intended to 'mean' anything.
+     * @return A uniquely defining string.
+     */
+    public String getDefinition();
+
+    public enum WorkingState {
+        New, Changed, Unchanged, Removed;
+    }
+}
\ No newline at end of file

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryUtil.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryUtil.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryUtil.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/RepositoryUtil.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository;
+
+public class RepositoryUtil
+{
+	/**
+	 * Before passing user input into an LDAP filter, some precautions need to be taken
+	 * (see section 3.2.6 of the OSGi core specification). This function escapes
+	 * illegal characters, and returns the resulting string.
+	 */
+    public static String escapeFilterValue(String value) {
+        return value.replaceAll("\\\\", "\\\\\\\\")
+            .replaceAll("\\(", "\\\\(")
+            .replaceAll("\\)", "\\\\)")
+            .replaceAll("\\*", "\\\\*");
+    }
+}
\ No newline at end of file

Added: ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/SessionFactory.java
URL: http://svn.apache.org/viewvc/ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/SessionFactory.java?rev=1357570&view=auto
==============================================================================
--- ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/SessionFactory.java (added)
+++ ace/sandbox/marrs/org.apache.ace.client.repository.api/src/org/apache/ace/client/repository/SessionFactory.java Thu Jul  5 12:09:30 2012
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.client.repository;
+
+/**
+ * Factory service for creating and destroying sessions. Sessions are identified by some kind
+ * of identification. This identification is also used as a service property in case there is
+ * one service for each session. The property name for this is <code>service.sid</code>, the
+ * service session ID. It is also used to listen to session specific events, in which case this
+ * same property is part of the actual event so it can be used in event filters.
+ */
+public interface SessionFactory
+{
+    /** Session ID for session specific service or event. */
+    public static final String SERVICE_SID = "service.sid";
+    /**
+     * Create a new session based on the supplied session ID.
+     *
+     * @param sessionID the session ID
+     */
+    public void createSession(String sessionID);
+    /**
+     * Destroy an existing session supplied on the supplied session ID.
+     *
+     * @param sessionID the session ID
+     */
+    public void destroySession(String sessionID);
+}
\ No newline at end of file



Mime
View raw message