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 2012/03/20 17:37:32 UTC

svn commit: r1302986 - in /ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest: LogEventSerializer.java RESTClientServlet.java RepositoryObjectSerializer.java Workspace.java

Author: marrs
Date: Tue Mar 20 16:37:32 2012
New Revision: 1302986

URL: http://svn.apache.org/viewvc?rev=1302986&view=rev
Log:
ACE-151 enhanced the REST API with more options to query the audit log (now separate from target) and to register and approve changes

Added:
    ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/LogEventSerializer.java   (with props)
Modified:
    ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RESTClientServlet.java
    ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryObjectSerializer.java
    ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Workspace.java

Added: ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/LogEventSerializer.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/LogEventSerializer.java?rev=1302986&view=auto
==============================================================================
--- ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/LogEventSerializer.java (added)
+++ ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/LogEventSerializer.java Tue Mar 20 16:37:32 2012
@@ -0,0 +1,80 @@
+/*
+ * 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.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import org.apache.ace.log.AuditEvent;
+import org.apache.ace.log.LogEvent;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+public class LogEventSerializer implements JsonSerializer<LogEvent> {
+
+	public JsonElement serialize(LogEvent e, Type typeOfSrc, JsonSerializationContext context) {
+        DateFormat format = SimpleDateFormat.getDateTimeInstance();
+        JsonObject event = new JsonObject();
+        event.addProperty("logId", e.getLogID());
+        event.addProperty("id", e.getID());
+        event.addProperty("time", format.format(new Date(e.getTime())));
+        event.addProperty("type", toAuditEventType(e.getType()));
+        JsonObject eventProperties = new JsonObject();
+        Dictionary p = e.getProperties();
+        Enumeration keyEnumeration = p.keys();
+        while (keyEnumeration.hasMoreElements()) {
+            Object key = keyEnumeration.nextElement();
+            eventProperties.addProperty(key.toString(), p.get(key).toString());
+        }
+        event.add("properties", eventProperties);
+        return event;
+    }
+
+    private String toAuditEventType(int type) {
+        switch (type) {
+            case AuditEvent.BUNDLE_INSTALLED: return "bundle installed";
+            case AuditEvent.BUNDLE_RESOLVED: return "bundle resolved";
+            case AuditEvent.BUNDLE_STARTED: return "bundle started";
+            case AuditEvent.BUNDLE_STOPPED: return "bundle stopped";
+            case AuditEvent.BUNDLE_UNRESOLVED: return "bundle unresolved";
+            case AuditEvent.BUNDLE_UPDATED: return "bundle updated";
+            case AuditEvent.BUNDLE_UNINSTALLED: return "bundle uninstalled";
+            case AuditEvent.BUNDLE_STARTING: return "bundle starting";
+            case AuditEvent.BUNDLE_STOPPING: return "bundle stopping";
+            case AuditEvent.FRAMEWORK_INFO: return "framework info";
+            case AuditEvent.FRAMEWORK_WARNING: return "framework warning";
+            case AuditEvent.FRAMEWORK_ERROR: return "framework error";
+            case AuditEvent.FRAMEWORK_REFRESH: return "framework refresh";
+            case AuditEvent.FRAMEWORK_STARTED: return "framework started";
+            case AuditEvent.FRAMEWORK_STARTLEVEL: return "framework startlevel";
+            case AuditEvent.DEPLOYMENTADMIN_INSTALL: return "deployment admin install";
+            case AuditEvent.DEPLOYMENTADMIN_UNINSTALL: return "deployment admin uninstall";
+            case AuditEvent.DEPLOYMENTADMIN_COMPLETE: return "deployment admin complete";
+            case AuditEvent.DEPLOYMENTCONTROL_INSTALL: return "deployment control install";
+            default: return Integer.toString(type);
+        }
+    }
+}

Propchange: ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/LogEventSerializer.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RESTClientServlet.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RESTClientServlet.java?rev=1302986&r1=1302985&r2=1302986&view=diff
==============================================================================
--- ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RESTClientServlet.java (original)
+++ ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RESTClientServlet.java Tue Mar 20 16:37:32 2012
@@ -34,6 +34,8 @@ import javax.servlet.http.HttpServletRes
 
 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.log.LogEvent;
 import org.apache.felix.dm.Component;
 import org.apache.felix.dm.DependencyManager;
 import org.osgi.service.cm.ConfigurationException;
@@ -48,7 +50,7 @@ import com.google.gson.JsonPrimitive;
  * Servlet that offers a REST client API.
  */
 public class RESTClientServlet extends HttpServlet implements ManagedService {
-    private static final long serialVersionUID = 5210711248294238039L;
+	private static final long serialVersionUID = 5210711248294238039L;
     /** Alias that redirects to the latest version automatically. */
     private static final String LATEST_FOLDER = "latest";
     /** Name of the folder where working copies are kept. */
@@ -67,6 +69,12 @@ public class RESTClientServlet extends H
     private static final String KEY_DEPLOYMENT_REPOSITORY_NAME = "deployment.repository.name";
     /** Name of the user to log in as. */
     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. */
+    private static final String ACTION_REGISTER = "register";
+    /** The action name for reading audit events. */
+    private static final String ACTION_AUDITEVENTS = "auditEvents";
 
     private static long m_sessionID = 1;
 
@@ -87,6 +95,7 @@ public class RESTClientServlet extends H
     public RESTClientServlet() {
         m_gson = (new GsonBuilder())
             .registerTypeHierarchyAdapter(RepositoryObject.class, new RepositoryObjectSerializer())
+            .registerTypeHierarchyAdapter(LogEvent.class, new LogEventSerializer())
             .create();
     }
     
@@ -107,6 +116,18 @@ public class RESTClientServlet extends H
                     return;
                 }
             }
+            else if (pathElements.length == 2) {
+            	JsonArray result = new JsonArray();
+            	result.add(new JsonPrimitive(Workspace.ARTIFACT));
+            	result.add(new JsonPrimitive(Workspace.ARTIFACT2FEATURE));
+            	result.add(new JsonPrimitive(Workspace.FEATURE));
+            	result.add(new JsonPrimitive(Workspace.FEATURE2DISTRIBUTION));
+            	result.add(new JsonPrimitive(Workspace.DISTRIBUTION));
+            	result.add(new JsonPrimitive(Workspace.DISTRIBUTION2TARGET));
+            	result.add(new JsonPrimitive(Workspace.TARGET));
+            	resp.getWriter().println(m_gson.toJson(result));
+            	return;
+            }
             else if (pathElements.length == 3) {
                 if (WORK_FOLDER.equals(pathElements[0])) {
                     Workspace workspace = getWorkspace(pathElements[1]);
@@ -115,7 +136,7 @@ public class RESTClientServlet extends H
                         List<RepositoryObject> objects = workspace.getRepositoryObjects(pathElements[2]);
                         JsonArray result = new JsonArray();
                         for (RepositoryObject ro : objects) {
-                            String identity = Workspace.getRepositoryObjectIdentity(ro);
+                            String identity = ro.getDefinition();
                             if (identity != null) {
                                 result.add(new JsonPrimitive(URLEncoder.encode(identity, "UTF-8")));
                             }
@@ -146,6 +167,61 @@ public class RESTClientServlet extends H
                     return;
                 }
             }
+            else if (pathElements.length == 5) {
+                if (WORK_FOLDER.equals(pathElements[0])) {
+                    Workspace workspace = getWorkspace(pathElements[1]);
+                    if (workspace != null) {
+                        String entityType = pathElements[2];
+                        String entityId = pathElements[3];
+                        String action = pathElements[4];
+                        RepositoryObject repositoryObject = workspace.getRepositoryObject(entityType, entityId);
+                        if (repositoryObject == null) {
+                            resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Repository object of type " + entityType + " and identity " + entityId + " not found.");
+                            return;
+                        }
+                        
+                        boolean isTarget = Workspace.TARGET.equals(entityType);
+						if (isTarget && ACTION_APPROVE.equals(action)) {
+                            resp.getWriter().println(m_gson.toJson(((StatefulTargetObject) repositoryObject).getStoreState()));
+                            return;
+                        }
+						else if (isTarget && ACTION_REGISTER.equals(action)) {
+                            resp.getWriter().println(m_gson.toJson(((StatefulTargetObject) repositoryObject).getRegistrationState()));
+                            return;
+                        }
+						else if (isTarget && ACTION_AUDITEVENTS.equals(action)) {
+							StatefulTargetObject target = (StatefulTargetObject) repositoryObject;
+							List<LogEvent> events = target.getAuditEvents();
+							String startValue = req.getParameter("start");
+							String maxValue = req.getParameter("max");
+							int start = (startValue == null) ? 0 : Integer.parseInt(startValue);
+							if (start < 0) {
+								start = 0;
+							}
+							if (start >= events.size()) {
+								start = events.size() - 1;
+							}
+							int max = (maxValue == null) ? 100 : Integer.parseInt(maxValue);
+							if (max < 1) {
+								max = 1;
+							}
+							int end = start + max;
+							if (end > events.size()) {
+								end = events.size();
+							}
+							List<LogEvent> selection = events.subList(start, end);
+                        	resp.getWriter().println(m_gson.toJson(selection));
+                        	return;
+                        }
+						else {
+                            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unknown action '" + action + "' for " + entityType + "/" + entityId);
+                            return;
+                        }
+                    }
+                    resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Could not find workspace: " + pathElements[1]);
+                    return;
+                }
+            }
             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
             return;
         }
@@ -201,7 +277,7 @@ public class RESTClientServlet extends H
                         try {
                             RepositoryValueObject data = m_gson.fromJson(req.getReader(), RepositoryValueObject.class);
                             RepositoryObject object = workspace.addRepositoryObject(pathElements[2], data.attributes, data.tags);
-                            String identity = Workspace.getRepositoryObjectIdentity(object);
+                            String identity = object.getDefinition();
                             if (identity != null) {
                                 resp.sendRedirect(buildPathFromElements(WORK_FOLDER, pathElements[1], pathElements[2], identity));
                             }
@@ -218,6 +294,39 @@ public class RESTClientServlet extends H
                     return;
                 }
             }
+            else if (pathElements.length == 5) {
+                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) {
+                            resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Repository object of type " + entityType + " and identity " + entityId + " not found.");
+                            return;
+                        }
+
+                        // the last element is the "command" to apply...
+                        String action = pathElements[4];
+
+                        if (Workspace.TARGET.equals(entityType) && ACTION_APPROVE.equals(action)) {
+                            StatefulTargetObject sto = workspace.approveTarget(repositoryObject);
+                            // Respond with the current store state...
+                            resp.getWriter().println(m_gson.toJson(sto.getStoreState()));
+                            return;
+                        } else if (Workspace.TARGET.equals(entityType) && ACTION_REGISTER.equals(action)) {
+                            StatefulTargetObject sto = workspace.registerTarget(repositoryObject);
+                            // Respond with the current registration state...
+                            resp.getWriter().println(m_gson.toJson(sto.getRegistrationState()));
+                            return;
+                        }
+                        
+                        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unknown action for " + pathElements[2]);
+                    }
+                    resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Could not find workspace: " + pathElements[1]);
+                    return;
+                }
+            }
         }
         resp.sendError(HttpServletResponse.SC_NOT_FOUND);
         return;

Modified: ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryObjectSerializer.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryObjectSerializer.java?rev=1302986&r1=1302985&r2=1302986&view=diff
==============================================================================
--- ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryObjectSerializer.java (original)
+++ ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/RepositoryObjectSerializer.java Tue Mar 20 16:37:32 2012
@@ -75,7 +75,7 @@ public class RepositoryObjectSerializer 
             state.addProperty("autoApprove", Boolean.toString(stateful.getAutoApprove()));
             JsonArray artifactsFromShop = new JsonArray();
             for (ArtifactObject a : stateful.getArtifactsFromShop()) {
-                artifactsFromShop.add(new JsonPrimitive(Workspace.getRepositoryObjectIdentity(a)));
+                artifactsFromShop.add(new JsonPrimitive(a.getDefinition()));
             }
             state.add("artifactsFromShop", artifactsFromShop);
             JsonArray artifactsFromDeployment = new JsonArray();
@@ -85,7 +85,6 @@ public class RepositoryObjectSerializer 
             state.add("artifactsFromDeployment", artifactsFromDeployment);
             state.addProperty("lastInstallVersion", stateful.getLastInstallVersion());
             state.addProperty("lastInstallSuccess", stateful.getLastInstallSuccess());
-            state.add("auditEvents", getAuditEvents(stateful));
             /* TODO getLicenses/AssocationsWith might not be that helpful since the data is also available in a different way */
             /* TODO some of this tends to show up as attributes as well, so we will need to do some filtering there */
             /* TODO some aspects of the state can be manipulated as well, we need to supply methods for that */

Modified: ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Workspace.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Workspace.java?rev=1302986&r1=1302985&r2=1302986&view=diff
==============================================================================
--- ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Workspace.java (original)
+++ ace/trunk/ace-client-rest/src/main/java/org/apache/ace/client/rest/Workspace.java Tue Mar 20 16:37:32 2012
@@ -90,7 +90,7 @@ public class Workspace {
             .setService(service, "(" + SessionFactory.SERVICE_SID + "=" + m_sessionID + ")")
             .setRequired(isRequired)
             .setInstanceBound(true)
-            );
+        );
     }
     
     private void addDependency(Component component, Class service, boolean isRequired) {
@@ -98,7 +98,7 @@ public class Workspace {
             .setService(service)
             .setRequired(isRequired)
             .setInstanceBound(true)
-            );
+        );
     }
     
     public void init(Component component) {
@@ -125,7 +125,6 @@ public class Workspace {
                 .addDeploymentRepository(new URL(m_repositoryURL), m_customerName, m_deploymentRepositoryName, true)
                 );
             m_repositoryAdmin.checkout();
-//            m_repositoryAdmin.revert();
         }
         catch (IOException e) {
             e.printStackTrace();
@@ -135,6 +134,10 @@ public class Workspace {
     
     public void destroy() {
     }
+    
+    public void checkout() throws IOException {
+    	m_repositoryAdmin.checkout();
+    }
 
     public void commit() throws IOException {
         m_repositoryAdmin.commit();
@@ -144,10 +147,6 @@ public class Workspace {
         return getObjectRepository(entityType).get(entityId);
     }
 
-    public static String getRepositoryObjectIdentity(RepositoryObject object) {
-        return object.getDefinition();
-    }
-
     public List<RepositoryObject> getRepositoryObjects(String entityType) {
         List list = getObjectRepository(entityType).get();
         if (list != null) {
@@ -203,7 +202,39 @@ public class Workspace {
             return getObjectRepository(entityType).create(attributes, tags);
         }
     }
-
+    
+    /**
+     * Approves a given stateful target object.
+     * <p>If the given repository object does <em>not</em> represent a stateful target object, this method will do nothing.</p>
+     * 
+     * @param repositoryObject the repository object to approve.
+     * @return the approved stateful target object, can be <code>null</code> only if the given repository object does not represent a {@link StatefulTargetObject}.
+     */
+    public StatefulTargetObject approveTarget(RepositoryObject repositoryObject) {
+        if (!(repositoryObject instanceof StatefulTargetObject)) {
+            return null;
+        }
+        StatefulTargetObject targetObject = (StatefulTargetObject) repositoryObject;
+        targetObject.approve();
+        return targetObject;
+    }
+
+    /**
+     * Registers a given stateful target object.
+     * <p>If the given repository object does <em>not</em> represent a stateful target object, this method will do nothing.</p>
+     * 
+     * @param repositoryObject the repository object to register.
+     * @return the registered stateful target object, can be <code>null</code> only if the given repository object does not represent a {@link StatefulTargetObject}.
+     */
+    public StatefulTargetObject registerTarget(RepositoryObject repositoryObject) {
+        if (!(repositoryObject instanceof StatefulTargetObject)) {
+            return null;
+        }
+        StatefulTargetObject targetObject = (StatefulTargetObject) repositoryObject;
+        targetObject.register();
+        return targetObject;
+    }
+    
     public void updateObjectWithData(String entityType, String entityId, RepositoryValueObject valueObject) {
         RepositoryObject repositoryObject = getRepositoryObject(entityType, entityId);
         // first handle the attributes