ace-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject svn commit: r1569429 [1/2] - in /ace/trunk: build/ org.apache.ace.client.rest/ org.apache.ace.client.rest/src/org/apache/ace/client/rest/ org.apache.ace.client.rest/test/org/apache/ace/client/rest/ org.apache.ace.client.workspace/ org.apache.ace.client...
Date Tue, 18 Feb 2014 17:00:33 GMT
Author: marrs
Date: Tue Feb 18 17:00:32 2014
New Revision: 1569429

URL: http://svn.apache.org/r1569429
Log:
ACE-456 applied the supplied patch

Added:
    ace/trunk/org.apache.ace.client.workspace/   (with props)
    ace/trunk/org.apache.ace.client.workspace/.classpath
    ace/trunk/org.apache.ace.client.workspace/.project
    ace/trunk/org.apache.ace.client.workspace/.settings/
    ace/trunk/org.apache.ace.client.workspace/.settings/org.eclipse.jdt.core.prefs
    ace/trunk/org.apache.ace.client.workspace/bnd.bnd
    ace/trunk/org.apache.ace.client.workspace/build.xml
    ace/trunk/org.apache.ace.client.workspace/src/
    ace/trunk/org.apache.ace.client.workspace/src/org/
    ace/trunk/org.apache.ace.client.workspace/src/org/apache/
    ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/
    ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/
    ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/
    ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/Workspace.java
    ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/WorkspaceManager.java
    ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/
    ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/Activator.java
    ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceImpl.java
    ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceManagerImpl.java
    ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/packageinfo
    ace/trunk/org.apache.ace.client.workspace/test/
    ace/trunk/org.apache.ace.client.workspace/test/org/
    ace/trunk/org.apache.ace.client.workspace/test/org/apache/
    ace/trunk/org.apache.ace.client.workspace/test/org/apache/ace/
    ace/trunk/org.apache.ace.client.workspace/test/org/apache/ace/client/
    ace/trunk/org.apache.ace.client.workspace/test/org/apache/ace/client/workspace/
    ace/trunk/org.apache.ace.client.workspace/test/org/apache/ace/client/workspace/impl/
    ace/trunk/org.apache.ace.client.workspace/test/org/apache/ace/client/workspace/impl/WorkspaceManagerImplTest.java
    ace/trunk/run-client/conf/org.apache.ace.client.workspace.cfg
    ace/trunk/run-server-allinone/conf/org.apache.ace.client.workspace.cfg
Removed:
    ace/trunk/org.apache.ace.client.rest/src/org/apache/ace/client/rest/Workspace.java
Modified:
    ace/trunk/build/bnd.bnd
    ace/trunk/org.apache.ace.client.rest/bnd.bnd
    ace/trunk/org.apache.ace.client.rest/src/org/apache/ace/client/rest/Activator.java
    ace/trunk/org.apache.ace.client.rest/src/org/apache/ace/client/rest/RESTClientServlet.java
    ace/trunk/org.apache.ace.client.rest/test/org/apache/ace/client/rest/RESTClientTest.java
    ace/trunk/run-client/client.bndrun
    ace/trunk/run-client/conf/org.apache.ace.client.rest.cfg
    ace/trunk/run-server-allinone/conf/org.apache.ace.client.rest.cfg
    ace/trunk/run-server-allinone/server-allinone.bndrun

Modified: ace/trunk/build/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/trunk/build/bnd.bnd?rev=1569429&r1=1569428&r2=1569429&view=diff
==============================================================================
--- ace/trunk/build/bnd.bnd (original)
+++ ace/trunk/build/bnd.bnd Tue Feb 18 17:00:32 2014
@@ -15,6 +15,7 @@
     org.apache.ace.client.repository.itest,\
     org.apache.ace.client.rest,\
     org.apache.ace.client.rest.itest,\
+    org.apache.ace.client.workspace,\
     org.apache.ace.configurator,\
     org.apache.ace.configurator.useradmin.itest,\
     org.apache.ace.connectionfactory,\

Modified: ace/trunk/org.apache.ace.client.rest/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.rest/bnd.bnd?rev=1569429&r1=1569428&r2=1569429&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.rest/bnd.bnd (original)
+++ ace/trunk/org.apache.ace.client.rest/bnd.bnd Tue Feb 18 17:00:32 2014
@@ -1,19 +1,15 @@
 -buildpath: osgi.core,\
 	osgi.cmpn,\
 	org.apache.felix.dependencymanager,\
-	org.apache.ace.connectionfactory;version=latest,\
-	org.apache.ace.authentication.api;version=latest,\
 	org.apache.ace.client.repository.api;version=latest,\
-	org.apache.ace.repository.api;version=latest,\
-	org.apache.ace.range.api;version=latest,\
-	org.apache.ace.test;version=latest,\
 	javax.servlet,\
 	gson;version=1.7.1,\
 	org.mockito.mockito-all,\
 	org.apache.felix.gogo.command,\
 	org.apache.felix.gogo.shell,\
 	org.apache.felix.gogo.runtime,\
-	org.apache.ace.feedback.common;version=latest
+	org.apache.ace.feedback.common;version=latest,\
+	org.apache.ace.client.workspace;version=latest
 Private-Package: org.apache.ace.client.rest,\
 	com.google.gson,\
 	com.google.gson.annotations,\
@@ -23,4 +19,4 @@ Private-Package: org.apache.ace.client.r
 Bundle-Activator: org.apache.ace.client.rest.Activator
 Bundle-Version: 1.0.0
 Bundle-Name: Apache ACE Client REST
-Bundle-Description: Provides a REST binding for the Apache ACE Client
\ No newline at end of file
+Bundle-Description: Provides a REST binding for the Apache ACE Client

Modified: ace/trunk/org.apache.ace.client.rest/src/org/apache/ace/client/rest/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.rest/src/org/apache/ace/client/rest/Activator.java?rev=1569429&r1=1569428&r2=1569429&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.rest/src/org/apache/ace/client/rest/Activator.java (original)
+++ ace/trunk/org.apache.ace.client.rest/src/org/apache/ace/client/rest/Activator.java Tue Feb 18 17:00:32 2014
@@ -22,7 +22,7 @@ import java.util.Properties;
 
 import javax.servlet.Servlet;
 
-import org.apache.ace.client.repository.SessionFactory;
+import org.apache.ace.client.workspace.WorkspaceManager;
 import org.apache.felix.dm.DependencyActivatorBase;
 import org.apache.felix.dm.DependencyManager;
 import org.apache.felix.service.command.CommandProcessor;
@@ -34,14 +34,11 @@ public class Activator extends Dependenc
     
     @Override
     public void init(BundleContext context, DependencyManager manager) throws Exception {
-		Properties props = new Properties();
-		props.put(CommandProcessor.COMMAND_SCOPE, "ace");
-		props.put(CommandProcessor.COMMAND_FUNCTION, new String[] { "cw", "rw" });
         manager.add(createComponent()
-            .setInterface(Servlet.class.getName(), props)
+            .setInterface(Servlet.class.getName(), null)
             .setImplementation(RESTClientServlet.class)
             .add(createServiceDependency()
-                .setService(SessionFactory.class)
+                .setService(WorkspaceManager.class)
                 .setRequired(true)
             )
             .add(createConfigurationDependency()
@@ -53,8 +50,8 @@ public class Activator extends Dependenc
                 .setRequired(false)
             )
         );
+
         Properties listProps = new Properties();
-        
         listProps.put(CommandProcessor.COMMAND_SCOPE, "coll");
         listProps.put(CommandProcessor.COMMAND_FUNCTION, new String[] { "first", "rest" });
         manager.add(createComponent()

Modified: ace/trunk/org.apache.ace.client.rest/src/org/apache/ace/client/rest/RESTClientServlet.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.rest/src/org/apache/ace/client/rest/RESTClientServlet.java?rev=1569429&r1=1569428&r2=1569429&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.rest/src/org/apache/ace/client/rest/RESTClientServlet.java (original)
+++ ace/trunk/org.apache.ace.client.rest/src/org/apache/ace/client/rest/RESTClientServlet.java Tue Feb 18 17:00:32 2014
@@ -23,28 +23,21 @@ import java.io.UnsupportedEncodingExcept
 import java.net.URLDecoder;
 import java.net.URLEncoder;
 import java.util.Dictionary;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import org.apache.ace.authentication.api.AuthenticationService;
 import org.apache.ace.client.repository.RepositoryObject;
-import org.apache.ace.client.repository.SessionFactory;
 import org.apache.ace.client.repository.stateful.StatefulTargetObject;
+import org.apache.ace.client.workspace.Workspace;
+import org.apache.ace.client.workspace.WorkspaceManager;
 import org.apache.ace.feedback.Event;
-import org.apache.felix.dm.Component;
-import org.apache.felix.dm.DependencyManager;
 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;
 
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
@@ -61,20 +54,7 @@ public class RESTClientServlet extends H
     private static final String LATEST_FOLDER = "latest";
     /** Name of the folder where working copies are kept. */
     private static final String WORK_FOLDER = "work";
-    /** A boolean denoting whether or not authentication is enabled. */
-    private static final String KEY_USE_AUTHENTICATION = "authentication.enabled";
-    /** URL of the repository to talk to. */
-    private static final String KEY_REPOSITORY_URL = "repository.url";
-    /** Name of the customer. */
-    private static final String KEY_CUSTOMER_NAME = "customer.name";
-    /** Name of the store repository. */
-    private static final String KEY_STORE_REPOSITORY_NAME = "store.repository.name";
-    /** Name of the distribution repository. */
-    private static final String KEY_DISTRIBUTION_REPOSITORY_NAME = "distribution.repository.name";
-    /** Name of the deployment repository. */
-    private static final String KEY_DEPLOYMENT_REPOSITORY_NAME = "deployment.repository.name";
-    /** Name of the user to log in as, in case no actual authentication is used. */
-    private static final String KEY_USER_NAME = "user.name";
+
     /** The action name for approving targets. */
     private static final String ACTION_APPROVE = "approve";
     /** The action name for registering targets. */
@@ -82,27 +62,11 @@ public class RESTClientServlet extends H
     /** The action name for reading audit events. */
     private static final String ACTION_AUDITEVENTS = "auditEvents";
 
-    private static long m_sessionID = 1;
-
     private volatile LogService m_logger;
-    private volatile DependencyManager m_dm;
-    private volatile SessionFactory m_sessionFactory;
-    
-	private volatile AuthenticationService m_authenticationService;
-	private volatile UserAdmin m_userAdmin;
-    
 
-    private final Map<String, Workspace> m_workspaces;
-    private final Map<String, Component> m_workspaceComponents;
+    private volatile WorkspaceManager workspaceManager;
+
     private final Gson m_gson;
-    
-    private boolean m_useAuthentication;
-    private String m_repositoryURL;
-    private String m_customerName;
-    private String m_storeRepositoryName;
-    private String m_targetRepositoryName;
-    private String m_deploymentRepositoryName;
-    private String m_serverUser;
 
     /**
      * Creates a new {@link RESTClientServlet} instance.
@@ -111,59 +75,7 @@ public class RESTClientServlet extends H
         m_gson = (new GsonBuilder())
             .registerTypeHierarchyAdapter(RepositoryObject.class, new RepositoryObjectSerializer())
             .registerTypeHierarchyAdapter(Event.class, new LogEventSerializer())
-            .create();
-        
-        m_workspaces = new HashMap<String, Workspace>();
-        m_workspaceComponents = new HashMap<String, Component>();
-    }
-    
-    public void init(Component component) {
-        addDependency(component, AuthenticationService.class, m_useAuthentication);
-        addDependency(component, UserAdmin.class, true);
-    }
-    
-    private void addDependency(Component component, Class service, boolean isRequired) {
-        component.add(component.getDependencyManager().createServiceDependency()
-            .setService(service)
-            .setRequired(isRequired)
-            .setInstanceBound(true)
-        );
-    }
-    
-    public void destroy() {
-    	Set<String> keySet = m_workspaces.keySet();
-    	if (!keySet.isEmpty()) {
-    		String[] keys = keySet.toArray(new String[keySet.size()]);
-    		for (String key : keys) {
-    			try {
-					removeWorkspace(key);
-				}
-    			catch (IOException e) {
-    				m_logger.log(LogService.LOG_WARNING, "Could not properly remove workspace.", e);
-				}
-    		}
-    	}
-    }
-
-    public void updated(Dictionary properties) throws ConfigurationException {
-        // First check whether all mandatory configuration keys are available...
-        String useAuth = getProperty(properties, KEY_USE_AUTHENTICATION);
-        if (useAuth == null || !("true".equalsIgnoreCase(useAuth) || "false".equalsIgnoreCase(useAuth))) {
-            throw new ConfigurationException(KEY_USE_AUTHENTICATION, "Missing or invalid value!");
-        }
-
-        // Note that configuration changes are only applied to new work areas, started after the
-        // configuration was changed. No attempt is done to "fix" existing work areas, although we
-        // might consider flushing/invalidating them.
-        synchronized (m_workspaces) {
-            m_useAuthentication = Boolean.valueOf(useAuth);
-            m_repositoryURL = getProperty(properties, KEY_REPOSITORY_URL, "http://localhost:8080/repository");
-            m_customerName = getProperty(properties, KEY_CUSTOMER_NAME, "apache");
-            m_storeRepositoryName = getProperty(properties, KEY_STORE_REPOSITORY_NAME, "shop");
-            m_targetRepositoryName = getProperty(properties, KEY_DISTRIBUTION_REPOSITORY_NAME, "target");
-            m_deploymentRepositoryName = getProperty(properties, KEY_DEPLOYMENT_REPOSITORY_NAME, "deployment");
-            m_serverUser = getProperty(properties, KEY_USER_NAME, "d");
-        }
+            .create();        
     }
 
     /**
@@ -210,36 +122,6 @@ public class RESTClientServlet extends H
     }
 
     /**
-     * Helper method to safely obtain a property value from the given dictionary.
-     * 
-     * @param properties the dictionary to retrieve the value from, can be <code>null</code>;
-     * @param key the name of the property to retrieve, cannot be <code>null</code>;
-     * @param defaultValue the default value to return in case the property does not exist, or the given dictionary was <code>null</code>.
-     * @return a property value, can be <code>null</code>.
-     */
-    String getProperty(Dictionary properties, String key, String defaultValue) {
-        String value = getProperty(properties, key);
-        return (value == null) ? defaultValue : value; 
-    }
-
-    /**
-     * Helper method to safely obtain a property value from the given dictionary.
-     * 
-     * @param properties the dictionary to retrieve the value from, can be <code>null</code>;
-     * @param key the name of the property to retrieve, cannot be <code>null</code>.
-     * @return a property value, can be <code>null</code>.
-     */
-    String getProperty(Dictionary properties, String key) {
-        if (properties != null) {
-            Object value = properties.get(key);
-            if (value != null && value instanceof String) {
-                return (String) value;
-            }
-        }
-        return null;
-    }
-
-    /**
      * @see javax.servlet.http.HttpServlet#doDelete(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
      */
     @Override
@@ -252,7 +134,7 @@ public class RESTClientServlet extends H
 
         final String id = pathElements[1];
 
-        Workspace workspace = getWorkspace(id);
+        Workspace workspace = workspaceManager.getWorkspace(id);
         if (workspace == null) {
             resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Could not find workspace: " + id);
             return;
@@ -260,7 +142,7 @@ public class RESTClientServlet extends H
 
         if (pathElements.length == 2) {
         	try {
-        		removeWorkspace(id);
+        		workspaceManager.removeWorkspace(id);
         	}
         	catch (IOException ioe) {
                 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Could not delete work area: " + ioe.getMessage());
@@ -303,7 +185,7 @@ public class RESTClientServlet extends H
             // path elements of length > 1...
             final String id = pathElements[1];
 
-            Workspace workspace = getWorkspace(id);
+            Workspace workspace = workspaceManager.getWorkspace(id);
             if (workspace == null) {
                 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Could not find workspace: " + id);
                 return;
@@ -350,11 +232,17 @@ public class RESTClientServlet extends H
         }
 
         if (pathElements.length == 1) {
-            createWorkspace(req, resp);
+            Workspace workspace = workspaceManager.createWorkspace(req.getParameterMap(), req);
+            if(workspace == null) {
+                resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+            }
+            else {
+                resp.sendRedirect(req.getServletPath() + "/" + buildPathFromElements(WORK_FOLDER, workspace.getSessionID()));
+            }
         }
         else {
             // more than one path elements...
-            Workspace workspace = getWorkspace(pathElements[1]);
+            Workspace workspace = workspaceManager.getWorkspace(pathElements[1]);
             if (workspace == null) {
                 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Could not find workspace: " + pathElements[1]);
                 return;
@@ -388,7 +276,7 @@ public class RESTClientServlet extends H
             return;
         }
 
-        Workspace workspace = getWorkspace(pathElements[1]);
+        Workspace workspace = workspaceManager.getWorkspace(pathElements[1]);
         if (workspace == null) {
             resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Could not find workspace: " + pathElements[1]);
             return;
@@ -426,7 +314,7 @@ public class RESTClientServlet extends H
      */
     private void createRepositoryObject(Workspace workspace, String entityType, RepositoryValueObject data, HttpServletRequest req, HttpServletResponse resp) throws IOException {
         try {
-            RepositoryObject object = workspace.addRepositoryObject(entityType, data.attributes, data.tags);
+            RepositoryObject object = workspace.createRepositoryObject(entityType, data.attributes, data.tags);
 
             resp.sendRedirect(req.getServletPath() + "/" + buildPathFromElements(WORK_FOLDER, workspace.getSessionID(), entityType, object.getDefinition()));
         }
@@ -436,48 +324,6 @@ public class RESTClientServlet extends H
         }
     }
     
-    /**
-     * Creates a new workspace.
-     * 
-     * @param resp the servlet response to write the response data to.
-     * @throws IOException in case of I/O errors.
-     */
-    private void createWorkspace(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
-        // TODO get data from post body (if no data, assume latest??) -> for now always assume latest
-        final String sessionID;
-        final Workspace workspace;
-        final Component component;
-
-        synchronized (m_workspaces) {
-            sessionID = "rest-" + m_sessionID++;
-            workspace = new Workspace(sessionID, m_repositoryURL, m_customerName, m_storeRepositoryName, m_targetRepositoryName, m_deploymentRepositoryName);
-            m_workspaces.put(sessionID, workspace);
-
-            component = m_dm.createComponent().setImplementation(workspace);
-            m_workspaceComponents.put(sessionID, component);
-        }
-        // any parameters supplied in this call are passed on to the session
-        // factory, so you can use these to configure your session
-        m_sessionFactory.createSession(sessionID, req.getParameterMap());
-        m_dm.add(component);
-        
-        
-        User user;
-        if (m_useAuthentication) {
-            // Use the authentication service to authenticate the given request...
-            user = m_authenticationService.authenticate(req);
-        } else {
-            // Use the "hardcoded" user to login with...
-            user = m_userAdmin.getUser("username", m_serverUser);
-        }
-        
-        if (user == null || !workspace.login(user)) {
-            resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
-        }
-        else {
-            resp.sendRedirect(req.getServletPath() + "/" + buildPathFromElements(WORK_FOLDER, sessionID));
-        }
-    }
 
     /**
      * Deletes a repository object from the current workspace.
@@ -515,19 +361,6 @@ public class RESTClientServlet extends H
         }
     }
 
-    /**
-     * Returns a workspace by its identification.
-     * 
-     * @param id the (session) identifier of the workspace to return.
-     * @return the workspace with requested ID, or <code>null</code> if no such workspace exists.
-     */
-    private Workspace getWorkspace(String id) {
-        Workspace workspace;
-        synchronized (m_workspaces) {
-            workspace = m_workspaces.get(id);
-        }
-        return workspace;
-    }
 
     /**
      * Performs an idempotent action on an repository object for the given workspace.
@@ -658,32 +491,7 @@ public class RESTClientServlet extends H
         }
     }
 
-    /**
-     * Removes the workspace with the given identifier.
-     * 
-     * @param id the identifier of the workspace to remove; 
-     * @param resp the servlet response to write the response data to.
-     * @throws IOException in case of I/O problems.
-     */
-    private void removeWorkspace(final String id) throws IOException {
-        final Workspace workspace;
-        final Component component;
-
-        synchronized (m_workspaces) {
-            workspace = m_workspaces.remove(id);
-            component = m_workspaceComponents.remove(id);
-        }
-
-        if ((workspace != null) && (component != null)) {
-            try {
-                workspace.logout();
-            }
-            finally {
-                m_dm.remove(component);
-                m_sessionFactory.destroySession(id);
-            }
-        }
-    }
+
 
     /**
      * Updates an existing repository object.
@@ -697,7 +505,7 @@ public class RESTClientServlet extends H
      */
     private void updateRepositoryObject(Workspace workspace, String entityType, String entityId, RepositoryValueObject data, HttpServletRequest req, HttpServletResponse resp) throws IOException {
         try {
-            workspace.updateObjectWithData(entityType, entityId, data);
+            workspace.updateRepositoryObject(entityType, entityId, data.attributes, data.tags);
 
             resp.sendRedirect(req.getServletPath() + "/" + buildPathFromElements(WORK_FOLDER, workspace.getSessionID(), entityType, entityId));
         }
@@ -738,49 +546,10 @@ public class RESTClientServlet extends H
             return null; // should never occur
         }
     }
-    
-    /*** SHELL COMMANDS ***/
 
-    public Workspace cw() throws Exception {
-    	return cw(m_customerName, m_customerName, m_customerName, null);
-    }
-
-    public Workspace cw(Map sessionConfiguration) throws Exception {
-    	return cw(m_customerName, m_customerName, m_customerName, sessionConfiguration);
+    @Override
+    public void updated(Dictionary properties) throws ConfigurationException {
+       // TODO Does anything need to happen here when the service endpoint is updated? 
     }
     
-	public Workspace cw(String storeCustomerName, String targetCustomerName, String deploymentCustomerName) throws Exception {
-		return cw(storeCustomerName, targetCustomerName, deploymentCustomerName, null);
-	}
-    
-	public Workspace cw(String storeCustomerName, String targetCustomerName, String deploymentCustomerName, Map sessionConfiguration) throws Exception {
-        final String sessionID;
-        final Workspace workspace;
-        final Component component;
-
-        synchronized (m_workspaces) {
-            sessionID = "shell-" + m_sessionID++;
-            workspace = new Workspace(sessionID, m_repositoryURL, storeCustomerName, m_storeRepositoryName, targetCustomerName, m_targetRepositoryName, deploymentCustomerName, m_deploymentRepositoryName);
-            m_workspaces.put(sessionID, workspace);
-
-            component = m_dm.createComponent().setImplementation(workspace);
-            m_workspaceComponents.put(sessionID, component);
-        }
-        m_sessionFactory.createSession(sessionID, sessionConfiguration);
-        m_dm.add(component);
-        
-        
-        // Use the "hardcoded" user to login with...
-        User user = m_userAdmin.getUser("username", m_serverUser);
-        if (user == null || !workspace.login(user)) {
-            return null;
-        }
-        else {
-            return workspace;
-        }
-    }
-	
-	public void rw(Workspace w) throws Exception {
-		removeWorkspace(w.getSessionID());
-	}
-}
+ }

Modified: ace/trunk/org.apache.ace.client.rest/test/org/apache/ace/client/rest/RESTClientTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.rest/test/org/apache/ace/client/rest/RESTClientTest.java?rev=1569429&r1=1569428&r2=1569429&view=diff
==============================================================================
--- ace/trunk/org.apache.ace.client.rest/test/org/apache/ace/client/rest/RESTClientTest.java (original)
+++ ace/trunk/org.apache.ace.client.rest/test/org/apache/ace/client/rest/RESTClientTest.java Tue Feb 18 17:00:32 2014
@@ -20,8 +20,6 @@ package org.apache.ace.client.rest;
 
 import static org.apache.ace.test.utils.TestUtils.UNIT;
 
-import java.util.Properties;
-
 import javax.servlet.http.HttpServletRequest;
 
 import org.mockito.Mockito;
@@ -29,25 +27,16 @@ import org.testng.Assert;
 import org.testng.annotations.Test;
 
 public class RESTClientTest {
-    @Test(groups = { UNIT })
-    public void testPathTransforms() {
-        String path = "one/two/last%20path";
-        RESTClientServlet s = new RESTClientServlet();
-        HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
-        Mockito.when(request.getPathInfo()).thenReturn(path);
-        String[] elements = s.getPathElements(request);
-        Assert.assertEquals(elements[0], "one");
-        Assert.assertEquals(elements[1], "two");
-        Assert.assertEquals(elements[2], "last path");
-        String result = s.buildPathFromElements(elements);
-        Assert.assertEquals(result, path);
-    }
-    
-    @Test(groups = { UNIT })
-    public void testPropertyGetter() {
-        RESTClientServlet s = new RESTClientServlet();
-        Assert.assertEquals(s.getProperty(new Properties() {{ put("key", "value"); }},  "key", "notused"), "value");
-        Assert.assertEquals(s.getProperty(new Properties() {{ put("unusedkey", "value"); }},  "key", "default"), "default");
-        Assert.assertEquals(s.getProperty(null,  "key", "default"), "default");
-    }
-}
+	@Test(groups = { UNIT })
+	public void testPathTransforms() {
+		String path = "one/two/last%20path";
+		RESTClientServlet s = new RESTClientServlet();
+		HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+		Mockito.when(request.getPathInfo()).thenReturn(path);
+		String[] elements = s.getPathElements(request);
+		Assert.assertEquals(elements[0], "one");
+		Assert.assertEquals(elements[1], "two");
+		Assert.assertEquals(elements[2], "last path");
+		String result = s.buildPathFromElements(elements);
+		Assert.assertEquals(result, path);
+	}}

Propchange: ace/trunk/org.apache.ace.client.workspace/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Feb 18 17:00:32 2014
@@ -0,0 +1,3 @@
+bin
+bin_test
+generated

Added: ace/trunk/org.apache.ace.client.workspace/.classpath
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/.classpath?rev=1569429&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.workspace/.classpath (added)
+++ ace/trunk/org.apache.ace.client.workspace/.classpath Tue Feb 18 17:00:32 2014
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" output="bin" path="src"/>
+	<classpathentry kind="src" output="bin_test" path="test"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
+	<classpathentry kind="con" path="aQute.bnd.classpath.container"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>

Added: ace/trunk/org.apache.ace.client.workspace/.project
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/.project?rev=1569429&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.workspace/.project (added)
+++ ace/trunk/org.apache.ace.client.workspace/.project Tue Feb 18 17:00:32 2014
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.apache.ace.client.workspace</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/trunk/org.apache.ace.client.workspace/.settings/org.eclipse.jdt.core.prefs
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/.settings/org.eclipse.jdt.core.prefs?rev=1569429&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.workspace/.settings/org.eclipse.jdt.core.prefs (added)
+++ ace/trunk/org.apache.ace.client.workspace/.settings/org.eclipse.jdt.core.prefs Tue Feb 18 17:00:32 2014
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6

Added: ace/trunk/org.apache.ace.client.workspace/bnd.bnd
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/bnd.bnd?rev=1569429&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.workspace/bnd.bnd (added)
+++ ace/trunk/org.apache.ace.client.workspace/bnd.bnd Tue Feb 18 17:00:32 2014
@@ -0,0 +1,11 @@
+-buildpath: osgi.core,\
+	osgi.cmpn,\
+	org.apache.felix.dependencymanager,\
+	org.apache.ace.client.repository.api;version=latest,\
+	org.apache.ace.test;version=latest,\
+	org.apache.felix.gogo.runtime
+	
+Bundle-Version: 1.0.0
+Bundle-Activator: org.apache.ace.client.workspace.impl.Activator
+Export-Package: org.apache.ace.client.workspace
+Private-Package: org.apache.ace.client.workspace.impl
\ No newline at end of file

Added: ace/trunk/org.apache.ace.client.workspace/build.xml
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/build.xml?rev=1569429&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.workspace/build.xml (added)
+++ ace/trunk/org.apache.ace.client.workspace/build.xml Tue Feb 18 17:00:32 2014
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="project" default="build">
+
+	<!-- -->
+
+	<import file="../cnf/build.xml" />
+</project>

Added: ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/Workspace.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/Workspace.java?rev=1569429&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/Workspace.java (added)
+++ ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/Workspace.java Tue Feb 18 17:00:32 2014
@@ -0,0 +1,336 @@
+/*
+ * 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.workspace;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ace.client.repository.ObjectRepository;
+import org.apache.ace.client.repository.RepositoryObject;
+import org.apache.ace.client.repository.object.Artifact2FeatureAssociation;
+import org.apache.ace.client.repository.object.ArtifactObject;
+import org.apache.ace.client.repository.object.Distribution2TargetAssociation;
+import org.apache.ace.client.repository.object.DistributionObject;
+import org.apache.ace.client.repository.object.Feature2DistributionAssociation;
+import org.apache.ace.client.repository.object.FeatureObject;
+import org.apache.ace.client.repository.stateful.StatefulTargetObject;
+import org.osgi.service.useradmin.User;
+
+/**
+ * Workspace represents the modifiable client-side state of an ACE repository. It facilitates a workflow whereby a
+ * repository can be checked out, queried, modified and committed back to the server.
+ * <p>
+ * Workspace has a generic API based on RepositoryObjects and their associations, as well as a more specific one dealing
+ * with resource processors, artifacts, features, distributions and targets. The latter is mostly intended for
+ * scripting, hence the shorthand notation of its method names:
+ * <p>
+ * Command syntax, first character is the "operation", then the "entity type" or "association". Note: not all
+ * combinations exist.<br>
+ * Operations: [c]reate, [l]ist, [d]elete, [u]pdate<br>
+ * Entities: [a]rtifact, [f]eature, [d]istribution, [t]arget<br>
+ * Associations: [a2f], [f2d], [d2t]<br>
+ * <p>
+ * Workspace objects are most commonly obtained from a WorkspaceManager acting on behalf of the client.
+ * 
+ * @see ObjectRepository
+ * @see WorkspaceManager
+ */
+public interface Workspace {
+    static final String ARTIFACT = "artifact";
+    static final String ARTIFACT2FEATURE = "artifact2feature";
+    static final String FEATURE = "feature";
+    static final String FEATURE2DISTRIBUTION = "feature2distribution";
+    static final String DISTRIBUTION = "distribution";
+    static final String DISTRIBUTION2TARGET = "distribution2target";
+    static final String TARGET = "target";
+
+    /**
+     * @return the session ID of this workspace, never <code>null</code>.
+     */
+    public String getSessionID();
+
+    /**
+     * Login to the repository as the specified User.
+     * 
+     * Note that if the login was not successful (as indicated by the return value of this method), modifying the state
+     * of the Workspace and then committing it may not work as intended.
+     * 
+     * @param user
+     *            the user
+     * @return true if the login was successful, false otherwise
+     */
+    public boolean login(User user);
+
+    /**
+     * Checkout the latest the state of the repository into this Workspace.
+     * 
+     * @throws IOException
+     *             in case of I/O problems.
+     */
+    public void checkout() throws IOException;
+
+    /**
+     * Commit the current state of this Workspace to the repository.
+     * 
+     * @throws IOException
+     *             in case of I/O problems.
+     */
+    public void commit() throws IOException;
+
+    /**
+     * Logout from the repository.
+     * 
+     * Only has any effect if there was a successful login earlier.
+     * 
+     * @throws IOException
+     *             in case of I/O problems.
+     */
+    public void logout() throws IOException;
+
+    /**
+     * Create a new RepositoryObject with the specified characteristics.
+     * 
+     * @param entityType
+     *            the type of the RepositoryObject
+     * @param attributes
+     *            the attributes of the RepositoryObject
+     * @param tags
+     *            the tags of the RepositoryObject
+     * @return a new RepositoryObject with the specified characteristics
+     * @throws IllegalArgumentException
+     *             when the ObjectRepository this Workspace represents would throw this same exception
+     */
+    public RepositoryObject createRepositoryObject(String entityType, Map<String, String> attributes,
+            Map<String, String> tags) throws IllegalArgumentException;
+
+    /**
+     * @param entityType
+     *            the type of the RepositoryObject
+     * @param entityId
+     *            the identifier of the RepositoryObject
+     * @return the RepositoryObject for the specified type and identifier
+     */
+    public RepositoryObject getRepositoryObject(String entityType, String entityId);
+
+    /**
+     * @param entityType
+     *            the type of RepositoryObjects to get
+     * @return all RepositoryObjects of the specified type. Might be empty, will not be <code>null</code>
+     */
+    public List<RepositoryObject> getRepositoryObjects(String entityType);
+
+    /**
+     * Update the RepositoryObject for the specified type and identifier with the specified attributes and tags.
+     * 
+     * The result of this call is that the specified RepositoryObject has only the specified attributes and tags.
+     * 
+     * @param entityType
+     *            the type of the RepositoryObject
+     * @param entityId
+     *            the identifier of the RepositoryObject
+     * @param attributes
+     *            the attributes of the RepositoryObject
+     * @param tags
+     *            the tags of the RepositoryObject
+     */
+    public void updateRepositoryObject(String entityType, String entityId, Map<String, String> attributes,
+            Map<String, String> tags);
+
+    /**
+     * Create an association of the specified between a left-hand side object and a right-hand side object with the
+     * specified cardinalities.
+     * 
+     * @param entityType
+     *            the association type
+     * @param leftEntityId
+     *            the identifier of the left-hand side object
+     * @param rightEntityId
+     *            the identifier of the right-hand side object
+     * @param leftCardinality
+     *            the cardinality of the left-hand side
+     * @param rightCardinality
+     *            the cardinality of the right-hand side
+     */
+    public void createAssocation(String entityType, String leftEntityId, String rightEntityId, String leftCardinality,
+            String rightCardinality);
+
+    /**
+     * Get the RepositoryObject that represents the left-hand side of the specified association.
+     * 
+     * For example, in an association linking an Artifact to a Feature, a Feature object would be the right-hand side
+     * 
+     * @param entityType
+     *            the association type
+     * @param entityId
+     *            the object identifier (note: not the association identifier)
+     * @return the left-hand side of the specified association, or null if no such object could be found
+     */
+    public RepositoryObject getLeft(String entityType, String entityId);
+
+    /**
+     * Get the RepositoryObject that represents the right-hand side of the specified association.
+     * 
+     * For example, in an association linking an Artifact to a Feature, a Feature object would be the right-hand side
+     * 
+     * @param entityType
+     *            the association type
+     * @param entityId
+     *            the object identifier (note: not the association identifier)
+     * @return the right-hand side of the specified association, or null if no such object could be found
+     */
+    public RepositoryObject getRight(String entityType, String entityId);
+
+    /**
+     * Remove the RepositoryObject with the specified type and identifier.
+     * 
+     * @param entityType
+     *            the object type
+     * @param entityId
+     *            the object indentifier
+     */
+    public void deleteRepositoryObject(String entityType, String entityId);
+
+    /*** resource processors ***/
+
+    public List<ArtifactObject> lrp();
+
+    public List<ArtifactObject> lrp(String filter) throws Exception;
+
+    /*** artifact ***/
+
+    public List<ArtifactObject> la();
+
+    public List<ArtifactObject> la(String filter) throws Exception;
+
+    public void ca(String name, String url, String bsn, String version);
+
+    public void ca(Map<String, String> attrs);
+
+    public void ca(Map<String, String> attrs, Map<String, String> tags);
+
+    public void da(RepositoryObject repositoryObject);
+
+    /*** artifact to feature association ***/
+
+    public List<Artifact2FeatureAssociation> la2f();
+
+    public List<Artifact2FeatureAssociation> la2f(String filter) throws Exception;
+
+    public void ca2f(String left, String right);
+
+    public void ca2f(String left, String right, String leftCardinality, String rightCardinalty);
+
+    public void da2f(Artifact2FeatureAssociation repositoryObject);
+
+    /*** feature ***/
+
+    public List<FeatureObject> lf();
+
+    public List<FeatureObject> lf(String filter) throws Exception;
+
+    public void cf(String name);
+
+    public void cf(Map<String, String> attrs);
+
+    public void cf(Map<String, String> attrs, Map<String, String> tags);
+
+    public void df(FeatureObject repositoryObject);
+
+    /*** feature to distribution association ***/
+
+    public List<Feature2DistributionAssociation> lf2d();
+
+    public List<Feature2DistributionAssociation> lf2d(String filter) throws Exception;
+
+    public void cf2d(String left, String right);
+
+    public void cf2d(String left, String right, String leftCardinality, String rightCardinalty);
+
+    public void df2d(Feature2DistributionAssociation repositoryObject);
+
+    /*** distribution ***/
+
+    public List<DistributionObject> ld();
+
+    public List<DistributionObject> ld(String filter) throws Exception;
+
+    public void cd(String name);
+
+    public void cd(Map<String, String> attrs);
+
+    public void cd(Map<String, String> attrs, Map<String, String> tags);
+
+    public void dd(DistributionObject repositoryObject);
+
+    /*** distribution to target association ***/
+
+    public List<Distribution2TargetAssociation> ld2t();
+
+    public List<Distribution2TargetAssociation> ld2t(String filter) throws Exception;
+
+    public void cd2t(String left, String right);
+
+    public void cd2t(String left, String right, String leftCardinality, String rightCardinalty);
+
+    public void dd2t(Distribution2TargetAssociation repositoryObject);
+
+    /*** target ***/
+
+    public List<StatefulTargetObject> lt();
+
+    public List<StatefulTargetObject> lt(String filter) throws Exception;
+
+    public RepositoryObject ct(String name);
+
+    public RepositoryObject ct(Map<String, String> attrs);
+
+    public RepositoryObject ct(Map<String, String> attrs, Map<String, String> tags);
+
+    public void dt(StatefulTargetObject repositoryObject);
+
+    /**
+     * Approves a given stateful target object.
+     * 
+     * @param targetObject
+     *            the target object to approve, cannot be <code>null</code>.
+     * @return the approved stateful target object, cannot be <code>null</code>.
+     */
+    public StatefulTargetObject approveTarget(StatefulTargetObject targetObject);
+
+    /**
+     * Registers a given stateful target object.
+     * 
+     * @param targetObject
+     *            the target object to register, cannot be <code>null</code>.
+     * @return the registered stateful target object, can be <code>null</code> only if the given target object is
+     *         already registered.
+     */
+    public StatefulTargetObject registerTarget(StatefulTargetObject targetObject);
+
+    /*** other/generic ***/
+
+    public void cas(String entityType, String leftEntityId, String rightEntityId, String leftCardinality,
+            String rightCardinality);
+
+    public boolean isModified() throws IOException;
+
+    public boolean isCurrent() throws IOException;
+
+}
\ No newline at end of file

Added: ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/WorkspaceManager.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/WorkspaceManager.java?rev=1569429&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/WorkspaceManager.java (added)
+++ ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/WorkspaceManager.java Tue Feb 18 17:00:32 2014
@@ -0,0 +1,167 @@
+/*
+ * 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.workspace;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * WorkspaceManager manages workspaces on behalf of a client.
+ * 
+ * It provides functionality to create, get and remove workspaces.
+ * 
+ * @see Workspace
+ */
+@SuppressWarnings("rawtypes")
+public interface WorkspaceManager {
+
+    /**
+     * Creates a new workspace using the specified session configuration and (optionally) authentication context
+     * objects.
+     * 
+     * @return a new workspace
+     * 
+     * @throws IOException
+     *             in case of I/O problems.
+     */
+    public Workspace createWorkspace(Map sessionConfiguration, Object... authenticationContext) throws IOException;
+
+    /**
+     * Get the workspace with the given identifier.
+     * 
+     * @param id
+     *            the (session) identifier of the workspace to return.
+     * @return the workspace with requested ID, or <code>null</code> if no such workspace exists.
+     */
+    public Workspace getWorkspace(String id) throws IOException;
+
+    /**
+     * Removes the workspace with the given identifier.
+     * 
+     * @param id
+     *            the (session) identifier of the workspace to remove.
+     * @throws IOException
+     *             in case of I/O problems.
+     */
+    public void removeWorkspace(String id) throws IOException;
+
+    /**
+     * Create a new workspace with the default configuration and the default authentication.
+     * 
+     * Shorthand intended for shell scripting.
+     * 
+     * @return a new workspace
+     * @throws IOException
+     *             in case of I/O problems.
+     * @see #createWorkspace(Map, Object...)
+     */
+    public Workspace cw() throws IOException;
+
+    /**
+     * Create a new workspace based on the specified session configuration and the default authentication.
+     * 
+     * Shorthand intended for shell scripting.
+     * 
+     * @param sessionConfiguration
+     *            the session configuration
+     * @return a new workspace
+     * @throws IOException
+     *             in case of I/O problems.
+     * @see #createWorkspace(Map, Object...)
+     */
+    public Workspace cw(Map sessionConfiguration) throws IOException;
+
+    /**
+     * Create a new workspace, using the specified customer names for the workspace. Otherwise using the default session
+     * configuration and the default authentication.
+     * 
+     * Shorthand intended for shell scripting.
+     * 
+     * @param storeCustomerName
+     *            the store customer name
+     * @param targetCustomerName
+     *            the target customer name
+     * @param deploymentCustomerName
+     *            the deployment customer name
+     * @return a new workspace
+     * @throws IOException
+     *             in case of I/O problems.
+     */
+    public Workspace cw(String storeCustomerName, String targetCustomerName, String deploymentCustomerName)
+            throws IOException;
+
+    /**
+     * Create a new workspace, using the specified customer names for the workspace. Otherwise using the specified
+     * session configuration and the default authentication.
+     * 
+     * Shorthand intended for shell scripting.
+     * 
+     * @param storeCustomerName
+     *            the store customer name
+     * @param targetCustomerName
+     *            the target customer name
+     * @param deploymentCustomerName
+     *            the deployment customer name
+     * @param sessionConfiguration
+     *            the session configuration
+     * @return a new workspace
+     * @throws IOException
+     *             in case of I/O problems.
+     */
+    public Workspace cw(String storeCustomerName, String targetCustomerName, String deploymentCustomerName,
+            Map sessionConfiguration) throws IOException;
+
+    /**
+     * Get the workspace with the given identifier.
+     * 
+     * Shorthand intended for shell scripting.
+     * 
+     * @param id
+     *            the (session) identifier of the workspace to return.
+     * @return the workspace with requested ID, or <code>null</code> if no such workspace exists.
+     * @see #getWorkspace(String)
+     */
+    public Workspace gw(String id) throws IOException;
+
+    /**
+     * Removes the workspace with the given identifier.
+     * 
+     * Shorthand intended for shell scripting.
+     * 
+     * @param id
+     *            the (session) identifier of the workspace to remove.
+     * @throws IOException
+     *             in case of I/O problems.
+     * @see #removeWorkspace(String)
+     */
+    public void rw(String id) throws IOException;
+
+    /**
+     * Removes the specified workspace.
+     * 
+     * Shorthand intended for shell scripting.
+     * 
+     * @param workspace
+     *            the workspace to remove.
+     * @throws IOException
+     *             in case of I/O problems.
+     */
+    public void rw(Workspace workspace) throws IOException;
+
+}
\ No newline at end of file

Added: ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/Activator.java?rev=1569429&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/Activator.java (added)
+++ ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/Activator.java Tue Feb 18 17:00:32 2014
@@ -0,0 +1,54 @@
+/*
+ * 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.workspace.impl;
+
+import java.util.Properties;
+
+import org.apache.ace.client.repository.SessionFactory;
+import org.apache.ace.client.workspace.WorkspaceManager;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.service.command.CommandProcessor;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+public class Activator extends DependencyActivatorBase {
+
+    /**
+     * Identifier for configuration settings.
+     */
+    public static final String WORKSPACE_PID = "org.apache.ace.client.workspace";
+
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        Properties props = new Properties();
+        props.put(CommandProcessor.COMMAND_SCOPE, "ace");
+        props.put(CommandProcessor.COMMAND_FUNCTION, new String[] { "cw", "gw", "rw" });
+        manager.add(createComponent().setInterface(WorkspaceManager.class.getName(), props)
+                .setImplementation(WorkspaceManagerImpl.class)
+                .add(createServiceDependency().setService(SessionFactory.class).setRequired(true))
+                .add(createConfigurationDependency().setPropagate(true).setPid(WORKSPACE_PID))
+                .add(createServiceDependency().setService(LogService.class).setRequired(false)));
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+        // nothing needs to be explicitly destroyed here at the moment
+    }
+}

Added: ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceImpl.java?rev=1569429&view=auto
==============================================================================
--- ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceImpl.java (added)
+++ ace/trunk/org.apache.ace.client.workspace/src/org/apache/ace/client/workspace/impl/WorkspaceImpl.java Tue Feb 18 17:00:32 2014
@@ -0,0 +1,733 @@
+/*
+ * 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.workspace.impl;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.ace.client.repository.Association;
+import org.apache.ace.client.repository.ObjectRepository;
+import org.apache.ace.client.repository.RepositoryAdmin;
+import org.apache.ace.client.repository.RepositoryAdminLoginContext;
+import org.apache.ace.client.repository.RepositoryObject;
+import org.apache.ace.client.repository.SessionFactory;
+import org.apache.ace.client.repository.helper.bundle.BundleHelper;
+import org.apache.ace.client.repository.object.Artifact2FeatureAssociation;
+import org.apache.ace.client.repository.object.ArtifactObject;
+import org.apache.ace.client.repository.object.Distribution2TargetAssociation;
+import org.apache.ace.client.repository.object.DistributionObject;
+import org.apache.ace.client.repository.object.Feature2DistributionAssociation;
+import org.apache.ace.client.repository.object.FeatureObject;
+import org.apache.ace.client.repository.repository.Artifact2FeatureAssociationRepository;
+import org.apache.ace.client.repository.repository.ArtifactRepository;
+import org.apache.ace.client.repository.repository.Distribution2TargetAssociationRepository;
+import org.apache.ace.client.repository.repository.DistributionRepository;
+import org.apache.ace.client.repository.repository.Feature2DistributionAssociationRepository;
+import org.apache.ace.client.repository.repository.FeatureRepository;
+import org.apache.ace.client.repository.stateful.StatefulTargetObject;
+import org.apache.ace.client.repository.stateful.StatefulTargetRepository;
+import org.apache.ace.client.workspace.Workspace;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.User;
+
+public class WorkspaceImpl implements Workspace {
+
+    private final String m_sessionID;
+    private final URL m_repositoryURL;
+    private final String m_storeCustomerName;
+    private final String m_distributionCustomerName;
+    private final String m_deploymentCustomerName;
+    private final String m_storeRepositoryName;
+    private final String m_distributionRepositoryName;
+    private final String m_deploymentRepositoryName;
+
+    private volatile BundleContext m_context;
+    private volatile DependencyManager m_manager;
+    private volatile RepositoryAdmin m_repositoryAdmin;
+    private volatile ArtifactRepository m_artifactRepository;
+    private volatile FeatureRepository m_featureRepository;
+    private volatile DistributionRepository m_distributionRepository;
+    private volatile StatefulTargetRepository m_statefulTargetRepository;
+    private volatile Artifact2FeatureAssociationRepository m_artifact2FeatureAssociationRepository;
+    private volatile Feature2DistributionAssociationRepository m_feature2DistributionAssociationRepository;
+    private volatile Distribution2TargetAssociationRepository m_distribution2TargetAssociationRepository;
+    private volatile LogService m_log;
+
+    public WorkspaceImpl(String sessionID, String repositoryURL, String customerName, String storeRepositoryName,
+            String distributionRepositoryName, String deploymentRepositoryName) throws MalformedURLException {
+        this(sessionID, repositoryURL, customerName, storeRepositoryName, customerName, distributionRepositoryName,
+                customerName, deploymentRepositoryName);
+    }
+
+    public WorkspaceImpl(String sessionID, String repositoryURL, String storeCustomerName, String storeRepositoryName,
+            String distributionCustomerName, String distributionRepositoryName, String deploymentCustomerName,
+            String deploymentRepositoryName) throws MalformedURLException {
+        m_sessionID = sessionID;
+        m_repositoryURL = new URL(repositoryURL);
+        m_storeCustomerName = storeCustomerName;
+        m_distributionCustomerName = deploymentCustomerName;
+        m_deploymentCustomerName = deploymentCustomerName;
+        m_storeRepositoryName = storeRepositoryName;
+        m_distributionRepositoryName = distributionRepositoryName;
+        m_deploymentRepositoryName = deploymentRepositoryName;
+    }
+
+    @Override
+    public String getSessionID() {
+        return m_sessionID;
+    }
+
+    private void addSessionDependency(Component component, Class<?> service, boolean isRequired) {
+        component.add(m_manager.createServiceDependency()
+                .setService(service, "(" + SessionFactory.SERVICE_SID + "=" + m_sessionID + ")")
+                .setRequired(isRequired).setInstanceBound(true));
+    }
+
+    private void addDependency(Component component, Class<?> service, boolean isRequired) {
+        component.add(m_manager.createServiceDependency().setService(service).setRequired(isRequired)
+                .setInstanceBound(true));
+    }
+
+    public void init(Component component) {
+        addSessionDependency(component, RepositoryAdmin.class, true);
+        addSessionDependency(component, ArtifactRepository.class, true);
+        addSessionDependency(component, FeatureRepository.class, true);
+        addSessionDependency(component, DistributionRepository.class, true);
+        addSessionDependency(component, StatefulTargetRepository.class, true);
+        addSessionDependency(component, Artifact2FeatureAssociationRepository.class, true);
+        addSessionDependency(component, Feature2DistributionAssociationRepository.class, true);
+        addSessionDependency(component, Distribution2TargetAssociationRepository.class, true);
+        addDependency(component, LogService.class, false);
+    }
+
+    public void start() {
+    }
+
+    public void destroy() {
+    }
+
+    @Override
+    public boolean login(User user) {
+        try {
+            RepositoryAdminLoginContext context = m_repositoryAdmin.createLoginContext(user);
+
+            context.add(
+                    context.createShopRepositoryContext().setLocation(m_repositoryURL).setCustomer(m_storeCustomerName)
+                            .setName(m_storeRepositoryName).setWriteable())
+                    .add(context.createTargetRepositoryContext().setLocation(m_repositoryURL)
+                            .setCustomer(m_distributionCustomerName).setName(m_distributionRepositoryName)
+                            .setWriteable())
+                    .add(context.createDeploymentRepositoryContext().setLocation(m_repositoryURL)
+                            .setCustomer(m_deploymentCustomerName).setName(m_deploymentRepositoryName).setWriteable());
+
+            m_repositoryAdmin.login(context);
+            m_repositoryAdmin.checkout();
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+            m_log.log(LogService.LOG_ERROR,
+                    "Could not login and checkout. Workspace will probably not work correctly.", e);
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public void checkout() throws IOException {
+        m_repositoryAdmin.checkout();
+    }
+
+    @Override
+    public void commit() throws IOException {
+        m_repositoryAdmin.commit();
+    }
+
+    @Override
+    public void logout() throws IOException {
+        try {
+            m_repositoryAdmin.logout(true);
+            m_repositoryAdmin.deleteLocal();
+        }
+        catch (IllegalStateException ise) {
+            m_log.log(LogService.LOG_DEBUG, "Nobody was logged into this session, continuing.");
+        }
+    }
+
+    @Override
+    public RepositoryObject getRepositoryObject(String entityType, String entityId) {
+        ObjectRepository<?> repo = getGenericObjectRepository(entityType);
+        return repo.get(entityId);
+    }
+
+    @Override
+    public List<RepositoryObject> getRepositoryObjects(String entityType) {
+        return getGenericRepositoryObjects(entityType);
+    }
+
+    @Override
+    public RepositoryObject createRepositoryObject(String entityType, Map<String, String> attributes,
+            Map<String, String> tags) throws IllegalArgumentException {
+        if (TARGET.equals(entityType)) {
+            ObjectRepository<StatefulTargetObject> repo = getGenericObjectRepository(TARGET);
+            StatefulTargetRepository statefulRepo = (StatefulTargetRepository) repo;
+            return statefulRepo.preregister(attributes, tags);
+        }
+        else {
+            prepareAssociationAttributes(entityType, attributes);
+            ObjectRepository<?> repo = getGenericObjectRepository(entityType);
+            return repo.create(attributes, tags);
+        }
+    }
+
+    // Note: this method looks very similar to updateAssociationAttributes. However, they are subtly different and can't
+    // be integrated given the current API.
+    private void prepareAssociationAttributes(String entityType, Map<String, String> attributes) {
+        if (ARTIFACT2FEATURE.equals(entityType) || FEATURE2DISTRIBUTION.equals(entityType)
+                || DISTRIBUTION2TARGET.equals(entityType)) {
+
+            String leftAttribute = attributes.get("left");
+            String rightAttribute = attributes.get("right");
+
+            RepositoryObject left = null;
+            if (leftAttribute != null) {
+                left = getLeft(entityType, leftAttribute);
+            }
+
+            RepositoryObject right = null;
+            if (rightAttribute != null) {
+                right = getRight(entityType, rightAttribute);
+            }
+
+            if (left != null) {
+                if (left instanceof StatefulTargetObject) {
+                    if (((StatefulTargetObject) left).isRegistered()) {
+                        attributes.put(Association.LEFT_ENDPOINT, ((StatefulTargetObject) left).getTargetObject()
+                                .getAssociationFilter(attributes));
+                    }
+                }
+                else {
+                    attributes.put(Association.LEFT_ENDPOINT, left.getAssociationFilter(attributes));
+                }
+            }
+            if (right != null) {
+                if (right instanceof StatefulTargetObject) {
+                    if (((StatefulTargetObject) right).isRegistered()) {
+                        attributes.put(Association.RIGHT_ENDPOINT, ((StatefulTargetObject) right).getTargetObject()
+                                .getAssociationFilter(attributes));
+                    }
+                }
+                else {
+                    attributes.put(Association.RIGHT_ENDPOINT, right.getAssociationFilter(attributes));
+                }
+            }
+        }
+    }
+
+    @Override
+    public void updateRepositoryObject(String entityType, String entityId, Map<String, String> attributes,
+            Map<String, String> tags) {
+        RepositoryObject repositoryObject = getRepositoryObject(entityType, entityId);
+        // first handle the attributes
+        for (Entry<String, String> attribute : attributes.entrySet()) {
+            String key = attribute.getKey();
+            String value = attribute.getValue();
+            // only add/update the attribute if it actually changed
+            if (!value.equals(repositoryObject.getAttribute(key))) {
+                repositoryObject.addAttribute(key, value);
+            }
+        }
+        Enumeration<String> keys = repositoryObject.getAttributeKeys();
+        while (keys.hasMoreElements()) {
+            String key = keys.nextElement();
+            if (!attributes.containsKey(key)) {
+                repositoryObject.removeAttribute(key);
+            }
+        }
+        updateAssociationAttributes(entityType, repositoryObject);
+        updateTags(tags, repositoryObject);
+    }
+
+    private void updateTags(Map<String, String> tags, RepositoryObject repositoryObject) {
+        Enumeration<String> keys;
+        // now handle the tags in a similar way
+        for (Entry<String, String> attribute : tags.entrySet()) {
+            String key = attribute.getKey();
+            String value = attribute.getValue();
+            // only add/update the tag if it actually changed
+            if (!value.equals(repositoryObject.getTag(key))) {
+                repositoryObject.addTag(key, value);
+            }
+        }
+        keys = repositoryObject.getTagKeys();
+        while (keys.hasMoreElements()) {
+            String key = keys.nextElement();
+            if (!tags.containsKey(key)) {
+                repositoryObject.removeTag(key);
+            }
+        }
+    }
+
+    // Note: this method looks very similar to prepareAssociationAttributes. However, they are subtly different and
+    // can't be integrated given the current API.
+    private void updateAssociationAttributes(String entityType, RepositoryObject repositoryObject) {
+        if (ARTIFACT2FEATURE.equals(entityType) || FEATURE2DISTRIBUTION.equals(entityType)
+                || DISTRIBUTION2TARGET.equals(entityType)) {
+            String leftAttribute = repositoryObject.getAttribute("left");
+            String rightAttribute = repositoryObject.getAttribute("right");
+
+            RepositoryObject left = null;
+            if (leftAttribute != null) {
+                left = getLeft(entityType, leftAttribute);
+            }
+
+            RepositoryObject right = null;
+            if (rightAttribute != null) {
+                right = getRight(entityType, rightAttribute);
+            }
+
+            if (left != null) {
+                if (left instanceof StatefulTargetObject) {
+                    if (((StatefulTargetObject) left).isRegistered()) {
+                        repositoryObject.addAttribute(
+                                Association.LEFT_ENDPOINT,
+                                ((StatefulTargetObject) left).getTargetObject().getAssociationFilter(
+                                        getAttributes(((StatefulTargetObject) left).getTargetObject())));
+                    }
+                }
+                else {
+                    repositoryObject.addAttribute(Association.LEFT_ENDPOINT,
+                            left.getAssociationFilter(getAttributes(left)));
+                }
+            }
+            if (right != null) {
+                if (right instanceof StatefulTargetObject) {
+                    if (((StatefulTargetObject) right).isRegistered()) {
+                        repositoryObject.addAttribute(
+                                Association.RIGHT_ENDPOINT,
+                                ((StatefulTargetObject) right).getTargetObject().getAssociationFilter(
+                                        getAttributes(((StatefulTargetObject) right).getTargetObject())));
+                    }
+                }
+                else {
+                    repositoryObject.addAttribute(Association.RIGHT_ENDPOINT,
+                            right.getAssociationFilter(getAttributes(right)));
+                }
+            }
+        }
+    }
+
+    private Map<String, String> getAttributes(RepositoryObject object) {
+        Map<String, String> result = new HashMap<String, String>();
+        for (Enumeration<String> keys = object.getAttributeKeys(); keys.hasMoreElements();) {
+            String key = keys.nextElement();
+            result.put(key, object.getAttribute(key));
+        }
+        return result;
+    }
+
+    @Override
+    public void createAssocation(String entityType, String leftEntityId, String rightEntityId, String leftCardinality,
+            String rightCardinality) {
+        Map<String, String> attrs = new HashMap<String, String>();
+        Map<String, String> tags = new HashMap<String, String>();
+        attrs.put(Association.LEFT_ENDPOINT, leftEntityId);
+        attrs.put(Association.LEFT_CARDINALITY, interpretCardinality(leftCardinality));
+        attrs.put(Association.RIGHT_ENDPOINT, rightEntityId);
+        attrs.put(Association.RIGHT_CARDINALITY, interpretCardinality(rightCardinality));
+        createRepositoryObject(entityType, attrs, tags);
+    }
+
+    @Override
+    public RepositoryObject getLeft(String entityType, String entityId) {
+        if (ARTIFACT2FEATURE.equals(entityType)) {
+            return getGenericObjectRepository(ARTIFACT).get(entityId);
+        }
+        else if (FEATURE2DISTRIBUTION.equals(entityType)) {
+            return getGenericObjectRepository(FEATURE).get(entityId);
+        }
+        else if (DISTRIBUTION2TARGET.equals(entityType)) {
+            return getGenericObjectRepository(DISTRIBUTION).get(entityId);
+        }
+        else {
+            // throws an exception in case of an illegal type!
+            getGenericObjectRepository(entityType);
+        }
+        return null;
+    }
+
+    @Override
+    public RepositoryObject getRight(String entityType, String entityId) {
+        if (ARTIFACT2FEATURE.equals(entityType)) {
+            return getGenericObjectRepository(FEATURE).get(entityId);
+        }
+        else if (FEATURE2DISTRIBUTION.equals(entityType)) {
+            return getGenericObjectRepository(DISTRIBUTION).get(entityId);
+        }
+        else if (DISTRIBUTION2TARGET.equals(entityType)) {
+            return getGenericObjectRepository(TARGET).get(entityId);
+        }
+        else {
+            // throws an exception in case of an illegal type!
+            getGenericObjectRepository(entityType);
+        }
+        return null;
+    }
+
+    @Override
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public void deleteRepositoryObject(String entityType, String entityId) {
+        ObjectRepository objectRepository = getGenericObjectRepository(entityType);
+        RepositoryObject repositoryObject = objectRepository.get(entityId);
+        // ACE-239: avoid null entities being passed in...
+        if (repositoryObject == null) {
+            throw new IllegalArgumentException("Could not find repository object!");
+        }
+
+        objectRepository.remove(repositoryObject);
+    }
+
+    private <T extends RepositoryObject> List<T> getGenericRepositoryObjects(String entityType) {
+        ObjectRepository<T> repo = getGenericObjectRepository(entityType);
+        List<T> list = repo.get();
+        if (list != null) {
+            return list;
+        }
+        else {
+            return Collections.emptyList();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T extends RepositoryObject> ObjectRepository<T> getGenericObjectRepository(String entityType) {
+        if (ARTIFACT.equals(entityType)) {
+            return (ObjectRepository<T>) m_artifactRepository;
+        }
+        if (ARTIFACT2FEATURE.equals(entityType)) {
+            return (ObjectRepository<T>) m_artifact2FeatureAssociationRepository;
+        }
+        if (FEATURE.equals(entityType)) {
+            return (ObjectRepository<T>) m_featureRepository;
+        }
+        if (FEATURE2DISTRIBUTION.equals(entityType)) {
+            return (ObjectRepository<T>) m_feature2DistributionAssociationRepository;
+        }
+        if (DISTRIBUTION.equals(entityType)) {
+            return (ObjectRepository<T>) m_distributionRepository;
+        }
+        if (DISTRIBUTION2TARGET.equals(entityType)) {
+            return (ObjectRepository<T>) m_distribution2TargetAssociationRepository;
+        }
+        if (TARGET.equals(entityType)) {
+            return (ObjectRepository<T>) m_statefulTargetRepository;
+        }
+        throw new IllegalArgumentException("Unknown entity type: " + entityType);
+    }
+
+    /*** SHELL COMMANDS ***/
+
+    @Override
+    public List<ArtifactObject> lrp() {
+        return m_artifactRepository.getResourceProcessors();
+    }
+
+    @Override
+    public List<ArtifactObject> lrp(String filter) throws Exception {
+        Filter f = m_context.createFilter(filter);
+        List<ArtifactObject> rps = m_artifactRepository.getResourceProcessors();
+        List<ArtifactObject> res = new LinkedList<ArtifactObject>();
+        for (ArtifactObject rp : rps) {
+            if (f.match(rp.getDictionary())) {
+                res.add(rp);
+            }
+        }
+        return res;
+    }
+
+    @Override
+    public List<ArtifactObject> la() {
+        return getGenericRepositoryObjects(ARTIFACT);
+    }
+
+    @Override
+    public List<ArtifactObject> la(String filter) throws Exception {
+        ObjectRepository<ArtifactObject> repo = getGenericObjectRepository(ARTIFACT);
+        return repo.get(m_context.createFilter(filter));
+    }
+
+    @Override
+    public void ca(String name, String url, String bsn, String version) {
+        Map<String, String> attrs = new HashMap<String, String>();
+        attrs.put(ArtifactObject.KEY_ARTIFACT_NAME, name);
+        attrs.put(ArtifactObject.KEY_URL, url);
+        attrs.put(ArtifactObject.KEY_MIMETYPE, BundleHelper.MIMETYPE);
+        attrs.put("Bundle-SymbolicName", bsn);
+        attrs.put("Bundle-Version", version);
+        ca(attrs);
+    }
+
+    @Override
+    public void ca(Map<String, String> attrs) {
+        ca(attrs, new HashMap<String, String>());
+    }
+
+    @Override
+    public void ca(Map<String, String> attrs, Map<String, String> tags) {
+        createRepositoryObject(ARTIFACT, attrs, tags);
+    }
+
+    @Override
+    public void da(RepositoryObject repositoryObject) {
+        deleteRepositoryObject(ARTIFACT, repositoryObject.getDefinition());
+    }
+
+    @Override
+    public List<Artifact2FeatureAssociation> la2f() {
+        return getGenericRepositoryObjects(ARTIFACT2FEATURE);
+    }
+
+    @Override
+    public List<Artifact2FeatureAssociation> la2f(String filter) throws Exception {
+        ObjectRepository<Artifact2FeatureAssociation> repo = getGenericObjectRepository(ARTIFACT2FEATURE);
+        return repo.get(m_context.createFilter(filter));
+    }
+
+    @Override
+    public void ca2f(String left, String right) {
+        ca2f(left, right, "1", "1");
+    }
+
+    @Override
+    public void ca2f(String left, String right, String leftCardinality, String rightCardinalty) {
+        cas(ARTIFACT2FEATURE, left, right, leftCardinality, rightCardinalty);
+    }
+
+    @Override
+    public void da2f(Artifact2FeatureAssociation repositoryObject) {
+        deleteRepositoryObject(ARTIFACT2FEATURE, repositoryObject.getDefinition());
+    }
+
+    @Override
+    public List<FeatureObject> lf() {
+        return getGenericRepositoryObjects(FEATURE);
+    }
+
+    @Override
+    public List<FeatureObject> lf(String filter) throws Exception {
+        ObjectRepository<FeatureObject> repo = getGenericObjectRepository(FEATURE);
+        return repo.get(m_context.createFilter(filter));
+    }
+
+    @Override
+    public void cf(String name) {
+        Map<String, String> attrs = new HashMap<String, String>();
+        attrs.put(FeatureObject.KEY_NAME, name);
+        cf(attrs);
+    }
+
+    @Override
+    public void cf(Map<String, String> attrs) {
+        cf(attrs, new HashMap<String, String>());
+    }
+
+    @Override
+    public void cf(Map<String, String> attrs, Map<String, String> tags) {
+        createRepositoryObject(FEATURE, attrs, tags);
+    }
+
+    @Override
+    public void df(FeatureObject repositoryObject) {
+        deleteRepositoryObject(FEATURE, repositoryObject.getDefinition());
+    }
+
+    @Override
+    public List<Feature2DistributionAssociation> lf2d() {
+        return getGenericRepositoryObjects(FEATURE2DISTRIBUTION);
+    }
+
+    @Override
+    public List<Feature2DistributionAssociation> lf2d(String filter) throws Exception {
+        ObjectRepository<Feature2DistributionAssociation> repo = getGenericObjectRepository(FEATURE2DISTRIBUTION);
+        return repo.get(m_context.createFilter(filter));
+    }
+
+    @Override
+    public void cf2d(String left, String right) {
+        cf2d(left, right, "1", "1");
+    }
+
+    @Override
+    public void cf2d(String left, String right, String leftCardinality, String rightCardinalty) {
+        cas(FEATURE2DISTRIBUTION, left, right, leftCardinality, rightCardinalty);
+    }
+
+    @Override
+    public void df2d(Feature2DistributionAssociation repositoryObject) {
+        deleteRepositoryObject(FEATURE2DISTRIBUTION, repositoryObject.getDefinition());
+    }
+
+    @Override
+    public List<DistributionObject> ld() {
+        return getGenericRepositoryObjects(DISTRIBUTION);
+    }
+
+    @Override
+    public List<DistributionObject> ld(String filter) throws Exception {
+        ObjectRepository<DistributionObject> repo = getGenericObjectRepository(DISTRIBUTION);
+        return repo.get(m_context.createFilter(filter));
+    }
+
+    @Override
+    public void cd(String name) {
+        Map<String, String> attrs = new HashMap<String, String>();
+        attrs.put(DistributionObject.KEY_NAME, name);
+        cd(attrs);
+    }
+
+    @Override
+    public void cd(Map<String, String> attrs) {
+        cd(attrs, new HashMap<String, String>());
+    }
+
+    @Override
+    public void cd(Map<String, String> attrs, Map<String, String> tags) {
+        createRepositoryObject(DISTRIBUTION, attrs, tags);
+    }
+
+    @Override
+    public void dd(DistributionObject repositoryObject) {
+        deleteRepositoryObject(DISTRIBUTION, repositoryObject.getDefinition());
+    }
+
+    @Override
+    public List<Distribution2TargetAssociation> ld2t() {
+        return getGenericRepositoryObjects(DISTRIBUTION2TARGET);
+    }
+
+    @Override
+    public List<Distribution2TargetAssociation> ld2t(String filter) throws Exception {
+        ObjectRepository<Distribution2TargetAssociation> repo = getGenericObjectRepository(DISTRIBUTION2TARGET);
+        return repo.get(m_context.createFilter(filter));
+    }
+
+    @Override
+    public void cd2t(String left, String right) {
+        cd2t(left, right, "1", "1");
+    }
+
+    @Override
+    public void cd2t(String left, String right, String leftCardinality, String rightCardinalty) {
+        cas(DISTRIBUTION2TARGET, left, right, leftCardinality, rightCardinalty);
+    }
+
+    @Override
+    public void dd2t(Distribution2TargetAssociation repositoryObject) {
+        deleteRepositoryObject(DISTRIBUTION2TARGET, repositoryObject.getDefinition());
+    }
+
+    @Override
+    public List<StatefulTargetObject> lt() {
+        return getGenericRepositoryObjects(TARGET);
+    }
+
+    @Override
+    public List<StatefulTargetObject> lt(String filter) throws Exception {
+        ObjectRepository<StatefulTargetObject> repo = getGenericObjectRepository(TARGET);
+        return repo.get(m_context.createFilter(filter));
+    }
+
+    @Override
+    public RepositoryObject ct(String name) {
+        Map<String, String> attrs = new HashMap<String, String>();
+        attrs.put(StatefulTargetObject.KEY_ID, name);
+        return ct(attrs);
+    }
+
+    @Override
+    public RepositoryObject ct(Map<String, String> attrs) {
+        return ct(attrs, new HashMap<String, String>());
+    }
+
+    @Override
+    public RepositoryObject ct(Map<String, String> attrs, Map<String, String> tags) {
+        return createRepositoryObject(TARGET, attrs, tags);
+    }
+
+    @Override
+    public void dt(StatefulTargetObject repositoryObject) {
+        deleteRepositoryObject(TARGET, repositoryObject.getDefinition());
+    }
+
+    @Override
+    public StatefulTargetObject approveTarget(StatefulTargetObject targetObject) {
+        targetObject.approve();
+        return targetObject;
+    }
+
+    @Override
+    public StatefulTargetObject registerTarget(StatefulTargetObject targetObject) {
+        if (targetObject.isRegistered()) {
+            return null;
+        }
+        targetObject.register();
+        return targetObject;
+    }
+
+    @Override
+    public boolean isModified() throws IOException {
+        return m_repositoryAdmin.isModified();
+    }
+
+    @Override
+    public boolean isCurrent() throws IOException {
+        return m_repositoryAdmin.isCurrent();
+    }
+
+    @Override
+    public void cas(String entityType, String leftEntityId, String rightEntityId, String leftCardinality,
+            String rightCardinality) {
+        createAssocation(entityType, leftEntityId, rightEntityId, leftCardinality, rightCardinality);
+    }
+
+    private static String interpretCardinality(String cardinality) {
+        if (cardinality != null && "N".equals(cardinality.toUpperCase())) {
+            return "" + Integer.MAX_VALUE;
+        }
+        else {
+            return cardinality;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return getSessionID();
+    }
+}



Mime
View raw message