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."