You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by bd...@apache.org on 2015/02/02 18:58:35 UTC

svn commit: r1656529 - in /sling/trunk: bundles/commons/testing/src/main/java/org/apache/sling/commons/testing/integration/ bundles/servlets/get/ bundles/servlets/get/src/main/java/org/apache/sling/servlets/get/impl/version/ bundles/servlets/get/src/ma...

Author: bdelacretaz
Date: Mon Feb  2 17:58:34 2015
New Revision: 1656529

URL: http://svn.apache.org/r1656529
Log:
SLING-4318 - new VersionInfoServlet, requires an OSGi config to be enabled. Contributed by Tomek Rękawek, thanks!

Added:
    sling/trunk/bundles/servlets/get/src/main/java/org/apache/sling/servlets/get/impl/version/
    sling/trunk/bundles/servlets/get/src/main/java/org/apache/sling/servlets/get/impl/version/VersionInfoServlet.java
    sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/VersionInfoServletTest.java
Modified:
    sling/trunk/bundles/commons/testing/src/main/java/org/apache/sling/commons/testing/integration/SlingIntegrationTestClient.java
    sling/trunk/bundles/servlets/get/pom.xml
    sling/trunk/bundles/servlets/get/src/main/resources/OSGI-INF/metatype/metatype.properties
    sling/trunk/launchpad/builder/src/main/bundles/list.xml

Modified: sling/trunk/bundles/commons/testing/src/main/java/org/apache/sling/commons/testing/integration/SlingIntegrationTestClient.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/commons/testing/src/main/java/org/apache/sling/commons/testing/integration/SlingIntegrationTestClient.java?rev=1656529&r1=1656528&r2=1656529&view=diff
==============================================================================
--- sling/trunk/bundles/commons/testing/src/main/java/org/apache/sling/commons/testing/integration/SlingIntegrationTestClient.java (original)
+++ sling/trunk/bundles/commons/testing/src/main/java/org/apache/sling/commons/testing/integration/SlingIntegrationTestClient.java Mon Feb  2 17:58:34 2015
@@ -22,8 +22,10 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpException;
 import org.apache.commons.httpclient.methods.DeleteMethod;
 import org.apache.commons.httpclient.methods.GetMethod;
 import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
@@ -246,4 +248,20 @@ public class SlingIntegrationTestClient
             throw new HttpStatusCodeException(expected, status, "POST", HttpTestBase.getResponseBodyAsStream(post, 0));
         }
     }
+    
+    public int post(String url, Map<String,String> properties) throws HttpException, IOException {
+        final PostMethod post = new PostMethod(url);
+        post.getParams().setContentCharset("UTF-8");
+        for(Entry<String, String> e : properties.entrySet()) {
+            post.addParameter(e.getKey(), e.getValue());
+        }
+        return httpClient.executeMethod(post);
+    }
+
+    public int get(String url) throws HttpException, IOException {
+        final GetMethod get = new GetMethod(url);
+        get.getParams().setContentCharset("UTF-8");
+        return httpClient.executeMethod(get);
+    }
+
 }

Modified: sling/trunk/bundles/servlets/get/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/get/pom.xml?rev=1656529&r1=1656528&r2=1656529&view=diff
==============================================================================
--- sling/trunk/bundles/servlets/get/pom.xml (original)
+++ sling/trunk/bundles/servlets/get/pom.xml Mon Feb  2 17:58:34 2015
@@ -96,6 +96,12 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-jcr-commons</artifactId>
+            <version>2.2.9</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
         </dependency>

Added: sling/trunk/bundles/servlets/get/src/main/java/org/apache/sling/servlets/get/impl/version/VersionInfoServlet.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/get/src/main/java/org/apache/sling/servlets/get/impl/version/VersionInfoServlet.java?rev=1656529&view=auto
==============================================================================
--- sling/trunk/bundles/servlets/get/src/main/java/org/apache/sling/servlets/get/impl/version/VersionInfoServlet.java (added)
+++ sling/trunk/bundles/servlets/get/src/main/java/org/apache/sling/servlets/get/impl/version/VersionInfoServlet.java Mon Feb  2 17:58:34 2015
@@ -0,0 +1,151 @@
+/*
+ * 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.sling.servlets.get.impl.version;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.VersionIterator;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.commons.json.io.JSONRenderer;
+import org.apache.sling.commons.json.jcr.JsonItemWriter;
+
+/**
+ * The <code>VersionInfoServlet</code> renders list of versions available for
+ * the current resource.
+ *
+ * At the moment only JCR nodes are supported.
+ */
+@Component(immediate=true, metatype=true, name="org.apache.sling.servlets.get.impl.version.VersionInfoServlet", label="%servlet.version.name", description="%servlet.version.description", policy=ConfigurationPolicy.REQUIRE)
+@Service(Servlet.class)
+@Properties({
+    @Property(name="service.description", value="Version info servlet"),
+    @Property(name="service.vendor", value="The Apache Software Foundation"),
+
+    @Property(name="sling.servlet.resourceTypes", value="sling/servlet/default", propertyPrivate=true),
+    @Property(name="sling.servlet.selectors", value="V"),
+    @Property(name="sling.servlet.methods", value="GET", propertyPrivate=true),
+    @Property(name="sling.servlet.extensions", value="json", propertyPrivate=true),
+})
+public class VersionInfoServlet extends SlingSafeMethodsServlet {
+
+    private static final long serialVersionUID = 1656887064561951302L;
+
+    /** Selector that means "pretty-print the output */
+    public static final String TIDY = "tidy";
+
+    /**
+     * Selector that causes hierarchy to be rendered as arrays instead of child objects - useful to preserve
+     * the order of those child objects
+     */
+    public static final String HARRAY = "harray";
+
+    /** How much to indent in tidy mode */
+    public static final int INDENT_SPACES = 2;
+
+    private final JSONRenderer renderer = new JSONRenderer();
+
+    public void doGet(SlingHttpServletRequest req, SlingHttpServletResponse resp) throws ServletException,
+            IOException {
+        resp.setContentType(req.getResponseContentType());
+        resp.setCharacterEncoding("UTF-8");
+        final boolean tidy = hasSelector(req, TIDY);
+        final boolean harray = hasSelector(req, HARRAY);
+
+        final JSONRenderer.Options opt = renderer.options().withIndent(tidy ? INDENT_SPACES : 0)
+                .withArraysForChildren(harray);
+        try {
+            resp.getWriter().write(renderer.prettyPrint(getJsonObject(req.getResource()), opt));
+        } catch (RepositoryException e) {
+            throw new ServletException(e);
+        } catch (JSONException e) {
+            throw new ServletException(e);
+        }
+    }
+
+    private JSONObject getJsonObject(Resource resource) throws RepositoryException, JSONException {
+        final JSONObject result = new JSONObject();
+        final Node node = resource.adaptTo(Node.class);
+        if (node == null || !node.isNodeType(JcrConstants.MIX_VERSIONABLE)) {
+            return result;
+        }
+
+        final VersionHistory history = node.getVersionHistory();
+        final Version baseVersion = node.getBaseVersion();
+        for (final VersionIterator it = history.getAllVersions(); it.hasNext();) {
+            final Version v = it.nextVersion();
+            final JSONObject obj = new JSONObject();
+            obj.put("created", createdDate(v));
+            obj.put("successors", getNames(v.getSuccessors()));
+            obj.put("predecessors", getNames(v.getPredecessors()));
+            obj.put("labels", Arrays.asList(history.getVersionLabels(v)));
+            obj.put("baseVersion", baseVersion.isSame(v));
+            result.put(v.getName(), obj);
+        }
+
+        final JSONObject wrapper = new JSONObject();
+        wrapper.put("versions", result);
+        return wrapper;
+    }
+
+    private static Collection<String> getNames(Version[] versions) throws RepositoryException {
+        final List<String> result = new ArrayList<String>();
+        for (Version s : versions) {
+            result.add(s.getName());
+        }
+        return result;
+    }
+
+    /** True if our request has the given selector */
+    private boolean hasSelector(SlingHttpServletRequest req, String selectorToCheck) {
+        for (String selector : req.getRequestPathInfo().getSelectors()) {
+            if (selectorToCheck.equals(selector)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static String createdDate(Node node) throws RepositoryException {
+        return JsonItemWriter.format(node.getProperty(JcrConstants.JCR_CREATED).getDate());
+    }
+
+}

Modified: sling/trunk/bundles/servlets/get/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/get/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=1656529&r1=1656528&r2=1656529&view=diff
==============================================================================
--- sling/trunk/bundles/servlets/get/src/main/resources/OSGI-INF/metatype/metatype.properties (original)
+++ sling/trunk/bundles/servlets/get/src/main/resources/OSGI-INF/metatype/metatype.properties Mon Feb  2 17:58:34 2015
@@ -26,6 +26,10 @@
 servlet.get.name = Apache Sling GET Servlet
 servlet.get.description = The Sling GET servlet is registered as the default \
  servlet to handle GET requests.
+ 
+servlet.version.name = Apache Sling Version Info Servlet
+servlet.version.description = The Sling Version Info Servlet renders list of \
+versions available for the current resource
 
 aliases.name = Extension Aliases
 aliases.description = The aliases can be used to map several extensions to a \

Modified: sling/trunk/launchpad/builder/src/main/bundles/list.xml
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/builder/src/main/bundles/list.xml?rev=1656529&r1=1656528&r2=1656529&view=diff
==============================================================================
--- sling/trunk/launchpad/builder/src/main/bundles/list.xml (original)
+++ sling/trunk/launchpad/builder/src/main/bundles/list.xml Mon Feb  2 17:58:34 2015
@@ -220,7 +220,7 @@
         <bundle>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.servlets.get</artifactId>
-            <version>2.1.10</version>
+            <version>2.1.11-SNAPSHOT</version>
         </bundle>
         <bundle>
             <groupId>org.apache.sling</groupId>

Added: sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/VersionInfoServletTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/VersionInfoServletTest.java?rev=1656529&view=auto
==============================================================================
--- sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/VersionInfoServletTest.java (added)
+++ sling/trunk/launchpad/integration-tests/src/main/java/org/apache/sling/launchpad/webapp/integrationtest/VersionInfoServletTest.java Mon Feb  2 17:58:34 2015
@@ -0,0 +1,99 @@
+package org.apache.sling.launchpad.webapp.integrationtest;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.httpclient.HttpException;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.commons.testing.integration.HttpTestBase;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+public class VersionInfoServletTest extends HttpTestBase {
+
+    public static final String TEST_BASE_PATH = "/sling-tests";
+
+    public static final String CONFIG_SERVLET = HTTP_BASE_URL + "/system/console/configMgr/org.apache.sling.servlets.get.impl.version.VersionInfoServlet";
+
+    private String postUrl;
+
+    private Map<String,String> params;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        postUrl = HTTP_BASE_URL + TEST_BASE_PATH + "/" + System.currentTimeMillis();
+        params = new HashMap<String,String>();
+        params.put("jcr:mixinTypes", "mix:versionable");
+    }
+
+    private String createVersionableNode() throws IOException {
+        params.put(":checkinNewVersionableNodes", "true");
+        final String location = testClient.createNode(postUrl + SlingPostConstants.DEFAULT_CREATE_SUFFIX, params);
+
+        final String content = getContent(location + ".txt", CONTENT_TYPE_PLAIN);
+        assertTrue("Node (" + location + ") should be checked in.", content.contains("jcr:isCheckedOut: false"));
+        return location;
+    }
+
+    public void testDisabledServlet() throws IOException, JSONException, InterruptedException {
+        deleteConfiguration();
+        waitUntilSlingIsStable();
+        getContent(createVersionableNode() + ".V.json", CONTENT_TYPE_HTML, null, 400);
+    }
+
+    public void testStandardVersionsList() throws IOException, JSONException, InterruptedException {
+        createConfiguration("V");
+        waitUntilSlingIsStable();
+        final JSONObject versions = new JSONObject(getContent(createVersionableNode() + ".V.json", CONTENT_TYPE_JSON));
+        assertTrue("Expecting versions subtree", versions.has("versions"));
+        assertTrue("Expecting root version", versions.getJSONObject("versions").has("jcr:rootVersion"));
+        assertTrue("Expecting version 1.0", versions.getJSONObject("versions").has("1.0"));
+
+        final JSONObject oneZero = versions.getJSONObject("versions").getJSONObject("1.0");
+        assertTrue("Expecting non-empty creation date", oneZero.get("created").toString().length() > 0);
+        assertEquals("Expecting no successors", 0, oneZero.getJSONArray("successors").length());
+        assertEquals("Expecting root version predecessor", "jcr:rootVersion", oneZero.getJSONArray("predecessors").getString(0));
+        assertEquals("Expecting no labels", 0, oneZero.getJSONArray("labels").length());
+        assertEquals("Expecting true baseVersion", "true", oneZero.getString("baseVersion"));
+    }
+
+    public void testHarrayVersionsList() throws Exception {
+        // No need to test everything in detail, just verify that the output
+        // is reformatted with the harray option
+        createConfiguration("V");
+        waitForSlingStartup();
+        waitUntilSlingIsStable();
+        final JSONObject versions = new JSONObject(getContent(createVersionableNode() + ".V.harray.json", CONTENT_TYPE_JSON));
+        assertTrue("Expecting children array", versions.has("__children__"));
+        assertEquals("Expecting versions object", "versions",
+                versions.getJSONArray("__children__").getJSONObject(0).get("__name__"));
+    }
+
+    private void createConfiguration(final String selector) throws IOException {
+        Map<String, String> properties = new HashMap<String, String>();
+        properties.put("apply", "true");
+        properties.put("sling.servlet.selectors", selector);
+        properties.put("propertylist", "sling.servlet.selectors");
+        assertEquals(302, testClient.post(CONFIG_SERVLET, properties));
+    }
+
+    private void deleteConfiguration() throws IOException {
+        Map<String, String> properties = new HashMap<String, String>();
+        properties.put("apply", "true");
+        properties.put("delete", "true");
+        assertEquals(200, testClient.post(CONFIG_SERVLET, properties));
+    }
+
+    private void waitUntilSlingIsStable() throws HttpException, IOException,
+            InterruptedException {
+        for (int i = 0; i < 10; i++) {
+            Thread.sleep(1000);
+            if (testClient.get(HTTP_BASE_URL  + "/.json") == 200) {
+                return;
+            }
+        }
+        fail("Sling instance fails to respond with status 200");
+    }
+}