You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ace.apache.org by ma...@apache.org on 2011/07/19 17:06:19 UTC

svn commit: r1148384 - in /incubator/ace/trunk/ace-client-rest: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/ace/ src/main/java/org/apache/ace/client/ src/main/java/org/apache/ace/client/rest/ s...

Author: marrs
Date: Tue Jul 19 15:06:17 2011
New Revision: 1148384

URL: http://svn.apache.org/viewvc?rev=1148384&view=rev
Log:
ACE-151 initial version, work in progress, but it's starting to work

Added:
    incubator/ace/trunk/ace-client-rest/
    incubator/ace/trunk/ace-client-rest/pom.xml
    incubator/ace/trunk/ace-client-rest/src/
    incubator/ace/trunk/ace-client-rest/src/main/
    incubator/ace/trunk/ace-client-rest/src/main/java/
    incubator/ace/trunk/ace-client-rest/src/main/java/org/
    incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/
    incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/
    incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/
    incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/
    incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Activator.java
    incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RESTClientServlet.java
    incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryObjectSerializer.java
    incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryValueObject.java
    incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Workspace.java
    incubator/ace/trunk/ace-client-rest/src/test/
    incubator/ace/trunk/ace-client-rest/src/test/java/
    incubator/ace/trunk/ace-client-rest/test.sh

Added: incubator/ace/trunk/ace-client-rest/pom.xml
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/ace-client-rest/pom.xml?rev=1148384&view=auto
==============================================================================
--- incubator/ace/trunk/ace-client-rest/pom.xml (added)
+++ incubator/ace/trunk/ace-client-rest/pom.xml Tue Jul 19 15:06:17 2011
@@ -0,0 +1,103 @@
+<?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-incubator-SNAPSHOT</version>
+        <relativePath>../pom/pom.xml</relativePath>
+    </parent>
+
+    <version>0.8.1-incubator-SNAPSHOT</version>
+    <artifactId>org.apache.ace.client.rest</artifactId>
+    <packaging>bundle</packaging>
+
+    <name>Apache ACE :: Client :: REST API</name>
+    <description />
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/incubator/ace/trunk/ace-client-rest</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/incubator/ace/trunk/ace-client-rest</developerConnection>
+        <url>http://svn.apache.org/repos/asf/incubator/ace/trunk/ace-client-rest</url>
+    </scm>
+
+    <properties>
+        <import.package>
+	        *
+        </import.package>
+        <private.package>
+            org.apache.ace.client.rest,
+            com.google.gson,
+            com.google.gson.*
+        </private.package>
+        <bundle.activator>org.apache.ace.client.rest.Activator</bundle.activator>
+    </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.repository.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.repository.ext</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.server.log.store</artifactId>
+        </dependency>
+         <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.range.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.client.repository.helper.bundle</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>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>1.7.1</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file

Added: incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Activator.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Activator.java?rev=1148384&view=auto
==============================================================================
--- incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Activator.java (added)
+++ incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Activator.java Tue Jul 19 15:06:17 2011
@@ -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.rest;
+
+import javax.servlet.http.HttpServlet;
+
+import org.apache.ace.client.repository.SessionFactory;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.log.LogService;
+
+public class Activator extends DependencyActivatorBase {
+    public static final String RESTCLIENT_PID = "org.apache.ace.client.rest";
+    
+    @Override
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        manager.add(createComponent()
+            .setInterface(HttpServlet.class.getName(), null)
+            .setImplementation(RESTClientServlet.class)
+            .add(createServiceDependency()
+                .setService(SessionFactory.class)
+                .setRequired(true)
+                )
+            .add(createConfigurationDependency()
+                .setPropagate(true)
+                .setPid(RESTCLIENT_PID)
+                )
+            .add(createServiceDependency()
+                .setService(LogService.class)
+                .setRequired(false)
+                )
+        );
+    }
+
+    @Override
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+    }
+}

Added: incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RESTClientServlet.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RESTClientServlet.java?rev=1148384&view=auto
==============================================================================
--- incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RESTClientServlet.java (added)
+++ incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RESTClientServlet.java Tue Jul 19 15:06:17 2011
@@ -0,0 +1,259 @@
+/*
+ * 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.rest;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.ace.client.repository.RepositoryObject;
+import org.apache.ace.client.repository.SessionFactory;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonPrimitive;
+
+/**
+ * Servlet that offers a REST client API.
+ */
+public class RESTClientServlet extends HttpServlet {
+    /** Alias that redirects to the latest version automatically. */
+    private static final String LATEST_FOLDER = "latest";
+    /** Name of the folder where working copies are kept. */
+    private static final String WORK_FOLDER = "work";
+    
+    private static long m_sessionID = 1;
+    
+    private volatile DependencyManager m_dm;
+    private volatile SessionFactory m_sessionFactory;
+    
+    private final Map<String, Workspace> m_workspaces = new HashMap<String, Workspace>();
+    private final Map<String, Component> m_workspaceComponents = new HashMap<String, Component>();
+    private Gson m_gson;
+    
+    public RESTClientServlet() {
+        m_gson = (new GsonBuilder())
+        .registerTypeHierarchyAdapter(RepositoryObject.class, new RepositoryObjectSerializer())
+        .create();
+    }
+    
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String[] pathElements = getPathElements(req);
+        if (pathElements == null || pathElements.length == 0) {
+            // TODO return a list of versions
+            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "Not implemented: list of versions");
+        }
+        else {
+            if (pathElements.length == 1) {
+                if (LATEST_FOLDER.equals(pathElements[0])) {
+                    // TODO redirect to latest version
+                    // resp.sendRedirect("notImplemented" /* to latest version */);
+                    resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, "Not implemented: redirect to latest version");
+                }
+            }
+            else if (pathElements.length == 3) {
+                if (WORK_FOLDER.equals(pathElements[0])) {
+                    Workspace workspace = getWorkspace(pathElements[1]);
+                    if (workspace != null) {
+                        // TODO add a feature to filter the list that is returned (query, paging, ...)
+                        List<RepositoryObject> objects = workspace.getRepositoryObjects(pathElements[2]);
+                        JsonArray result = new JsonArray();
+                        for (RepositoryObject ro : objects) {
+                            result.add(new JsonPrimitive(URLEncoder.encode(ro.getAssociationFilter(null), "UTF-8")));
+                        }
+                        resp.getWriter().println(m_gson.toJson(result));
+                        return;
+                    }
+                    resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Could not find workspace: " + pathElements[1]);
+                }
+            }
+            else if (pathElements.length == 4) {
+                if (WORK_FOLDER.equals(pathElements[0])) {
+                    Workspace workspace = getWorkspace(pathElements[1]);
+                    if (workspace != null) {
+                        String entityType = pathElements[2];
+                        String entityId = pathElements[3];
+                        RepositoryObject repositoryObject = workspace.getRepositoryObject(entityType, entityId);
+                        if (repositoryObject == null) {
+                            // TODO not found
+                            resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Repository object of type " + entityType + " and identity " + entityId + " not found.");
+                        }
+                        
+                        resp.getWriter().println(m_gson.toJson(repositoryObject));
+                        return;
+                    }
+                    resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Could not find workspace: " + pathElements[1]);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String[] pathElements = getPathElements(req);
+        if (pathElements != null) {
+            if (pathElements.length == 1) {
+                if (WORK_FOLDER.equals(pathElements[0])) {
+                    // TODO get data from post body (if no data, assume latest??) -> for now always assume latest
+                    String sessionID;
+                    Workspace workspace;
+                    Component component;
+                    synchronized (m_workspaces) {
+                        sessionID = "rest-" + m_sessionID++;
+                        // TODO OBR with or without trailing slash?
+                        // TODO this needs to come from configuration
+                        workspace = new Workspace(sessionID, "http://localhost:8080/repository", "http://localhost:8080/obr", "apache", "shop", "gateway", "deployment", "d");
+                        m_workspaces.put(sessionID, workspace);
+                        component = m_dm.createComponent().setImplementation(workspace);
+                        m_workspaceComponents.put(sessionID, component);
+                    }
+                    m_sessionFactory.createSession(sessionID);
+                    m_dm.add(component);
+                    resp.sendRedirect(WORK_FOLDER + "/" + sessionID);
+                    return;
+                }
+            }
+            else if (pathElements.length == 2) {
+                if (WORK_FOLDER.equals(pathElements[0])) {
+                    Workspace workspace = getWorkspace(pathElements[1]);
+                    if (workspace != null) {
+                        try {
+                            workspace.commit();
+                            return;
+                        }
+                        catch (Exception e) {
+                            e.printStackTrace();
+                            resp.sendError(HttpServletResponse.SC_CONFLICT, "Commit failed: " + e.getMessage());
+                            return;
+                        }
+                    }
+                    else {
+                        // return error
+                        System.out.println("Failed...");
+                    }
+                }
+            }
+            else if (pathElements.length == 3) {
+                if (WORK_FOLDER.equals(pathElements[0])) {
+                    Workspace workspace = getWorkspace(pathElements[1]);
+                    if (workspace != null) {
+                        try {
+                            RepositoryValueObject data = m_gson.fromJson(req.getReader(), RepositoryValueObject.class);
+                            RepositoryObject object = workspace.addRepositoryObject(pathElements[2], data.attributes, data.tags);
+                            resp.sendRedirect(WORK_FOLDER + "/" + pathElements[1] + "/" + pathElements[2] + "/" + URLEncoder.encode(object.getAssociationFilter(null), "UTF-8"));
+                            return;
+                        }
+                        catch (IllegalArgumentException e) {
+                            e.printStackTrace();
+                        }
+                    }
+                    resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Could not add entity of type " + pathElements[2]);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String[] pathElements = getPathElements(req);
+        if (pathElements != null) {
+            if (pathElements.length == 4) {
+                if (pathElements[0].equals(WORK_FOLDER)) {
+                    long id = Long.parseLong(pathElements[1]);
+                    // TODO check if pE[2] is one of the entities we know
+                    long entityId = Long.parseLong(pathElements[3]);
+                    // TODO check if pE[3] is a valid entity id, update it if it is
+                }
+            }
+        }
+    }
+    
+    @Override
+    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        String[] pathElements = getPathElements(req);
+        if (pathElements != null) {
+            if (pathElements.length == 2) {
+                if (WORK_FOLDER.equals(pathElements[0])) {
+                    String id = pathElements[1];
+                    Workspace workspace;
+                    Component component;
+                    synchronized (m_workspaces) {
+                        workspace = m_workspaces.remove(id);
+                        component = m_workspaceComponents.remove(id);
+                    }
+                    if (workspace != null && component != null) {
+                        // TODO delete the work area
+                        m_dm.remove(component);
+                        m_sessionFactory.destroySession(id);
+                    }
+                    else {
+                        // return error
+                    }
+                }
+            }
+            else if (pathElements.length == 4) {
+                if (WORK_FOLDER.equals(pathElements[0])) {
+                    long id = Long.parseLong(pathElements[1]);
+                    // TODO check if pE[2] is one of the entities we know
+                    long entityId = Long.parseLong(pathElements[3]);
+                    // TODO check if pE[3] is a valid entity id and delete it if it is
+                }
+            }
+        }
+    }
+
+    private Workspace getWorkspace(String id) {
+        Workspace workspace;
+        synchronized (m_workspaces) {
+            workspace = m_workspaces.get(id);
+        }
+        return workspace;
+    }
+
+    private String[] getPathElements(HttpServletRequest req) {
+        String path = req.getPathInfo();
+        if (path.startsWith("/") && path.length() > 1) {
+            path = path.substring(1);
+        }
+        if (path.endsWith("/") && path.length() > 1) {
+            path = path.substring(0, path.length() - 1);
+        }
+        String[] pathElements = path.split("/");
+        try {
+            for (int i = 0; i < pathElements.length; i++) {
+                pathElements[i] = URLDecoder.decode(pathElements[i], "UTF-8");
+            }
+        }
+        catch (UnsupportedEncodingException e) {}
+        return pathElements;
+    }
+}

Added: incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryObjectSerializer.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryObjectSerializer.java?rev=1148384&view=auto
==============================================================================
--- incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryObjectSerializer.java (added)
+++ incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryObjectSerializer.java Tue Jul 19 15:06:17 2011
@@ -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.rest;
+
+import java.lang.reflect.Type;
+import java.util.Enumeration;
+
+import org.apache.ace.client.repository.RepositoryObject;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+/**
+ * 
+ */
+public class RepositoryObjectSerializer implements JsonSerializer<RepositoryObject> {
+    public JsonElement serialize(RepositoryObject repositoryObject, Type featureType, JsonSerializationContext context) {
+        JsonObject result = new JsonObject();
+        // first add all attributes
+        Enumeration<String> keys = repositoryObject.getAttributeKeys();
+        JsonObject attr = new JsonObject();
+        while (keys.hasMoreElements()) {
+            String key = keys.nextElement();
+            attr.addProperty(key, repositoryObject.getAttribute(key));
+        }
+        result.add("attributes", attr);
+        // then add all tags
+        keys = repositoryObject.getTagKeys();
+        JsonObject tags = new JsonObject();
+        while (keys.hasMoreElements()) {
+            String key = keys.nextElement();
+            tags.addProperty(key, repositoryObject.getTag(key));
+        }
+        result.add("tags", tags);
+        return result;
+    }
+}
\ No newline at end of file

Added: incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryValueObject.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryValueObject.java?rev=1148384&view=auto
==============================================================================
--- incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryValueObject.java (added)
+++ incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryValueObject.java Tue Jul 19 15:06:17 2011
@@ -0,0 +1,29 @@
+/*
+ * 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.rest;
+
+import java.util.Map;
+
+/**
+ * A value object that is used to store incoming JSON data.
+ */
+public class RepositoryValueObject {
+    public Map<String, String> attributes;
+    public Map<String, String> tags;
+}
\ No newline at end of file

Added: incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Workspace.java
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Workspace.java?rev=1148384&view=auto
==============================================================================
--- incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Workspace.java (added)
+++ incubator/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Workspace.java Tue Jul 19 15:06:17 2011
@@ -0,0 +1,236 @@
+/*
+ * 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.rest;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ace.client.repository.RepositoryAdmin;
+import org.apache.ace.client.repository.RepositoryObject;
+import org.apache.ace.client.repository.SessionFactory;
+import org.apache.ace.client.repository.repository.Artifact2GroupAssociationRepository;
+import org.apache.ace.client.repository.repository.ArtifactRepository;
+import org.apache.ace.client.repository.repository.GatewayRepository;
+import org.apache.ace.client.repository.repository.Group2LicenseAssociationRepository;
+import org.apache.ace.client.repository.repository.GroupRepository;
+import org.apache.ace.client.repository.repository.License2GatewayAssociationRepository;
+import org.apache.ace.client.repository.repository.LicenseRepository;
+import org.apache.ace.client.repository.stateful.StatefulGatewayRepository;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.log.LogService;
+import org.osgi.service.useradmin.User;
+import org.osgi.service.useradmin.UserAdmin;
+
+public class Workspace {
+    private static final String ARTIFACT = "artifact";
+    private static final String ARTIFACT2FEATURE = "artifact2feature";
+    private static final String FEATURE = "feature";
+    private static final String FEATURE2DISTRIBUTION = "feature2distribution";
+    private static final String DISTRIBUTION = "distribution";
+    private static final String DISTRIBUTION2TARGET = "distribution2target";
+    private static final String TARGET = "target";
+    private final String m_sessionID;
+    private final String m_repositoryURL;
+    private final String m_obrURL;
+    private final String m_customerName;
+    private final String m_storeRepositoryName;
+    private final String m_licenseRepositoryName;
+    private final String m_deploymentRepositoryName;
+    private final String m_serverUser;
+    private volatile DependencyManager m_manager;
+    private volatile RepositoryAdmin m_repositoryAdmin;
+    private volatile ArtifactRepository m_artifactRepository;
+    private volatile GroupRepository m_featureRepository;
+    private volatile LicenseRepository m_distributionRepository;
+    private volatile StatefulGatewayRepository m_statefulTargetRepository;
+    private volatile GatewayRepository m_targetRepository;
+    private volatile Artifact2GroupAssociationRepository m_artifact2FeatureAssociationRepository;
+    private volatile Group2LicenseAssociationRepository m_feature2DistributionAssociationRepository;
+    private volatile License2GatewayAssociationRepository m_distribution2TargetAssociationRepository;
+    private volatile UserAdmin m_userAdmin;
+    private volatile LogService m_log;
+
+    public Workspace(String sessionID, String repositoryURL, String obrURL, String customerName, String storeRepositoryName, String licenseRepositoryName, String deploymentRepositoryName, String serverUser) {
+        m_sessionID = sessionID;
+        m_repositoryURL = repositoryURL;
+        m_obrURL = obrURL;
+        m_customerName = customerName;
+        m_storeRepositoryName = storeRepositoryName;
+        m_licenseRepositoryName = licenseRepositoryName;
+        m_deploymentRepositoryName = deploymentRepositoryName;
+        m_serverUser = serverUser;
+    }
+    
+    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, GroupRepository.class, true);
+        addSessionDependency(component, LicenseRepository.class, true);
+        addSessionDependency(component, GatewayRepository.class, true);
+        addSessionDependency(component, StatefulGatewayRepository.class, true);
+        addSessionDependency(component, Artifact2GroupAssociationRepository.class, true);
+        addSessionDependency(component, Group2LicenseAssociationRepository.class, true);
+        addSessionDependency(component, License2GatewayAssociationRepository.class, true);
+        addDependency(component, UserAdmin.class, true);
+        addDependency(component, LogService.class, false);
+    }
+    
+    public void start() {
+        try {
+            User user = m_userAdmin.getUser("username", m_serverUser);
+            m_repositoryAdmin.login(m_repositoryAdmin.createLoginContext(user)
+                .setObrBase(new URL(m_obrURL))
+                .addShopRepository(new URL(m_repositoryURL), m_customerName, m_storeRepositoryName, true)
+                .addGatewayRepository(new URL(m_repositoryURL), m_customerName, m_licenseRepositoryName, true)
+                .addDeploymentRepository(new URL(m_repositoryURL), m_customerName, m_deploymentRepositoryName, true)
+                );
+            m_repositoryAdmin.checkout();
+//            m_repositoryAdmin.revert();
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+            m_log.log(LogService.LOG_ERROR, "Could not login and checkout. Workspace will probably not work correctly.", e);
+        }
+    }
+    
+    public void destroy() {
+    }
+
+    public void commit() throws IOException {
+        m_repositoryAdmin.commit();
+    }
+
+    public RepositoryObject getRepositoryObject(String entityType, String entityId) {
+        RepositoryObject result = null;
+        try {
+            List list = null;
+            Filter filter = FrameworkUtil.createFilter(entityId);
+            if (ARTIFACT.equals(entityType)) {
+                list = m_artifactRepository.get(filter);
+            }
+            if (ARTIFACT2FEATURE.equals(entityType)) {
+                list = m_artifact2FeatureAssociationRepository.get(filter);
+            }
+            if (FEATURE.equals(entityType)) {
+                list = m_featureRepository.get(filter);
+            }
+            if (FEATURE2DISTRIBUTION.equals(entityType)) {
+                list = m_feature2DistributionAssociationRepository.get(filter);
+            }
+            if (DISTRIBUTION.equals(entityType)) {
+                list = m_distributionRepository.get(filter);
+            }
+            if (DISTRIBUTION2TARGET.equals(entityType)) {
+                list = m_distribution2TargetAssociationRepository.get(filter);
+            }
+            if (TARGET.equals(entityType)) {
+                list = m_statefulTargetRepository.get(filter);
+            }
+            if (list != null && list.size() == 1) {
+                return (RepositoryObject) list.get(0);
+            }
+        }
+        catch (InvalidSyntaxException e) {
+            e.printStackTrace();
+        }
+        return result;
+    }
+
+    public List<RepositoryObject> getRepositoryObjects(String entityType) {
+        List list = null;
+        if (ARTIFACT.equals(entityType)) {
+            list = m_artifactRepository.get();
+        }
+        if (ARTIFACT2FEATURE.equals(entityType)) {
+            list = m_artifact2FeatureAssociationRepository.get();
+        }
+        if (FEATURE.equals(entityType)) {
+            list = m_featureRepository.get();
+        }
+        if (FEATURE2DISTRIBUTION.equals(entityType)) {
+            list = m_feature2DistributionAssociationRepository.get();
+        }
+        if (DISTRIBUTION.equals(entityType)) {
+            list = m_distributionRepository.get();
+        }
+        if (DISTRIBUTION2TARGET.equals(entityType)) {
+            list = m_distribution2TargetAssociationRepository.get();
+        }
+        if (TARGET.equals(entityType)) {
+            list = m_statefulTargetRepository.get();
+        }
+        if (list != null) {
+            return list;
+        }
+        else {
+            return Collections.EMPTY_LIST;
+        }
+    }
+
+    public RepositoryObject addRepositoryObject(String entityType, Map<String, String> attributes, Map<String, String> tags) throws IllegalArgumentException{
+        if (ARTIFACT.equals(entityType)) {
+            return m_artifactRepository.create(attributes, tags);
+        }
+        if (ARTIFACT2FEATURE.equals(entityType)) {
+            // TODO this is a fairly low level way to create associations
+            return m_artifact2FeatureAssociationRepository.create(attributes, tags);
+        }
+        if (FEATURE.equals(entityType)) {
+            return m_featureRepository.create(attributes, tags);
+        }
+        if (FEATURE2DISTRIBUTION.equals(entityType)) {
+            // TODO this is a fairly low level way to create associations
+            return m_feature2DistributionAssociationRepository.create(attributes, tags);
+        }
+        if (DISTRIBUTION.equals(entityType)) {
+            return m_distributionRepository.create(attributes, tags);
+        }
+        if (DISTRIBUTION2TARGET.equals(entityType)) {
+            // TODO this is a fairly low level way to create associations
+            return m_distribution2TargetAssociationRepository.create(attributes, tags);
+        }
+        if (TARGET.equals(entityType)) {
+            return m_targetRepository.create(attributes, tags);
+        }
+        throw new IllegalArgumentException("Unknown entity type: " + entityType);
+    }
+}

Added: incubator/ace/trunk/ace-client-rest/test.sh
URL: http://svn.apache.org/viewvc/incubator/ace/trunk/ace-client-rest/test.sh?rev=1148384&view=auto
==============================================================================
--- incubator/ace/trunk/ace-client-rest/test.sh (added)
+++ incubator/ace/trunk/ace-client-rest/test.sh Tue Jul 19 15:06:17 2011
@@ -0,0 +1,46 @@
+#!/bin/bash
+#
+# Test script that sends out REST commands
+#
+
+# Check out a new workspace
+echo "*** Creating new workspace..."
+WORK=`curl -s -d dummy_data -w %{redirect_url} http://localhost:8080/client/work`
+echo "Workspace is ${WORK}"
+
+# Add two random features (might fail, name is actually random)
+#curl -v -d "{ attributes: { name: 'feature-${RANDOM}', description: 'a random feature' }, tags: { generated: 'true'}}" ${WORK}/feature
+#curl -v -d "{ attributes: { name: 'feature-${RANDOM}', description: 'another random feature' }, tags: { generated: 'true'}}" ${WORK}/feature
+
+# Add a feature, a distribution and an association between the two
+echo "*** Adding feature, distribution and association..."
+FEAT=`curl -v -d "{ attributes: { name: 'feature-${RANDOM}', description: 'a feature' }, tags: {}}" -w %{redirect_url} ${WORK}/feature`
+FEATID=`echo ${FEAT##*/} | perl -MURI::Escape -lne 'print uri_unescape($_)'`
+echo "Feature is ${FEAT} => ${FEATID}"
+DIST=`curl -v -d "{ attributes: { name: 'distribution-${RANDOM}', description: 'a distribution' }, tags: {}}" -w %{redirect_url} ${WORK}/distribution`
+DISTID=`echo ${DIST##*/} | perl -MURI::Escape -lne 'print uri_unescape($_)'`
+echo "Distribution is ${DIST} => ${DISTID}"
+ASSOC=`curl -v -d "{ attributes: { leftEndpoint: '${FEATID}', leftCardinality: '1', rightEndpoint: '${DISTID}', rightCardinality: '1' }, tags: {}}" -w %{redirect_url} ${WORK}/feature2distribution`
+echo "Association is ${ASSOC}"
+
+# Get a list of artifacts
+#curl ${WORK}/artifact
+#curl ${WORK}/artifact/%28%26%28Bundle-SymbolicName%3Dnet.luminis.android.desktop%29%28Bundle-Version%3D1.0.0%29%29
+
+# Add a random artifact (does not upload to OBR yet)
+#echo "*** Adding a new, random artifact..."
+#RND=$RANDOM
+#BSN=org.apache.bundle${RND}
+#VERSION=1.0.0
+#NAME=${BSN}-${VERSION}
+#curl -v -d "{attributes: { artifactName: '${NAME}' , mimetype: 'application/vnd.osgi.bundle', Bundle-Name: '${BSN}', Bundle-SymbolicName: '${BSN}', Bundle-Version: '${VERSION}', url: 'http://localhost:8080/obr/${NAME}.jar', artifactDescription: 'coolio', processorPid: '' }, tags: { generated: 'true' }}" ${WORK}/artifact
+
+# Create a target
+TARGET=`curl -v -d "{ attributes: { id: 'target-${RANDOM}', autoapprove: 'true' }, tags: {}}" -w %{redirect_url} ${WORK}/target`
+echo "Target is ${TARGET}"
+
+# Commit the workspace
+echo "*** Committing workspace..."
+curl -v -d dummy_data ${WORK}
+
+echo "*** Done."