Author: bdelacretaz
Date: Fri May 13 14:02:03 2016
New Revision: 1743676

URL: http://svn.apache.org/viewvc?rev=1743676&view=rev
Log:
SLING-5725 - Remove o.a.s.testing.tools dependency in o.a.s.testing.clients and 
merge OSGi console clients - contribued by Andrei Dulvac, thanks!

Added:
    
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/poller/PathPoller.java
Removed:
    
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/WebconsoleClient.java
Modified:
    sling/trunk/testing/http/clients/pom.xml
    
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInstaller.java
    
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/OsgiConsoleClient.java

Modified: sling/trunk/testing/http/clients/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/trunk/testing/http/clients/pom.xml?rev=1743676&r1=1743675&r2=1743676&view=diff
==============================================================================
--- sling/trunk/testing/http/clients/pom.xml (original)
+++ sling/trunk/testing/http/clients/pom.xml Fri May 13 14:02:03 2016
@@ -69,17 +69,6 @@
 
     <dependencies>
         <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.testing.tools</artifactId>
-            <version>1.0.12</version>
-            <exclusions>
-                <exclusion>
-                    <groupId>org.apache.httpcomponents</groupId>
-                    <artifactId>httpcore</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
         </dependency>
@@ -144,5 +133,18 @@
             <artifactId>org.apache.sling.xss</artifactId>
             <version>1.0.4</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.json</artifactId>
+            <version>2.0.16</version>
+        </dependency>
+
+        <!-- For tests -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.12</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>

Modified: 
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInstaller.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInstaller.java?rev=1743676&r1=1743675&r2=1743676&view=diff
==============================================================================
--- 
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInstaller.java
 (original)
+++ 
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInstaller.java
 Fri May 13 14:02:03 2016
@@ -16,171 +16,202 @@
  */
 package org.apache.sling.testing.clients.osgi;
 
-import org.osgi.framework.Constants;
+import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.util.poller.AbstractPoller;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.jar.JarInputStream;
-import java.util.jar.Manifest;
 
 
-/** Utility that installs and starts additional bundles for testing */ 
+/**
+ * Utility for installing and starting additional bundles for testing
+ */
 public class BundlesInstaller {
     private final Logger log = LoggerFactory.getLogger(getClass());
-    private final WebconsoleClient webconsoleClient;
+    private final OsgiConsoleClient osgiConsoleClient;
     public static final String ACTIVE_STATE = "active";
-    
-    public BundlesInstaller(WebconsoleClient wcc) {
-        webconsoleClient = wcc;
-    }
-   
-    public boolean isInstalled(File bundleFile) throws Exception {
-        final String bundleSymbolicName = getBundleSymbolicName(bundleFile);
-        try{
-            log.debug("Checking if installed: "+bundleSymbolicName);
-            webconsoleClient.checkBundleInstalled(bundleSymbolicName, 1);
-            // if this succeeds, then there's no need to install again
-            log.debug("Already installed: "+bundleSymbolicName);
+
+    public BundlesInstaller(OsgiConsoleClient cc) {
+        osgiConsoleClient = cc;
+    }
+
+    /**
+     * Checks if a bundle is installed or not. Does not retry.
+     * @param bundleFile
+     * @return
+     * @throws ClientException
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    public boolean isInstalled(File bundleFile) throws ClientException, 
InterruptedException, IOException {
+        final String bundleSymbolicName = 
OsgiConsoleClient.getBundleSymbolicName(bundleFile);
+        log.debug("Checking if installed: " + bundleSymbolicName);
+        boolean installed = 
osgiConsoleClient.checkBundleInstalled(bundleSymbolicName, 1000, 1);
+        // if this succeeds, then there's no need to install again
+        if (installed) {
+            log.debug("Already installed: " + bundleSymbolicName);
             return true;
-        } catch(AssertionError e) {
-            log.debug("Not yet installed: "+bundleSymbolicName);
+        } else {
+            log.debug("Not yet installed: " + bundleSymbolicName);
             return false;
         }
-
     }
-    
-    /** Check if the installed version matches the one of the bundle (file) **/
-    public boolean isInstalledWithSameVersion(File bundleFile) throws 
Exception {
-        final String bundleSymbolicName = getBundleSymbolicName(bundleFile);
-        final String versionOnServer = 
webconsoleClient.getBundleVersion(bundleSymbolicName);
-        final String versionInBundle = getBundleVersion(bundleFile);
+
+    /**
+     * Check if the installed version matches the one of the bundle (file)
+     * @param bundleFile
+     * @return
+     * @throws Exception
+     */
+    public boolean isInstalledWithSameVersion(File bundleFile) throws 
ClientException, IOException {
+        final String bundleSymbolicName = 
OsgiConsoleClient.getBundleSymbolicName(bundleFile);
+        final String versionOnServer = 
osgiConsoleClient.getBundleVersion(bundleSymbolicName);
+        final String versionInBundle = 
OsgiConsoleClient.getBundleVersionFromFile(bundleFile);
         if (versionOnServer.equals(versionInBundle)) {
             return true;
         } else {
-            log.info("Bundle installed doesn't match: "+bundleSymbolicName+
-                    ", versionOnServer="+versionOnServer+", 
versionInBundle="+versionInBundle);
+            log.warn("Installed bundle doesn't match: {}, versionOnServer={}, 
versionInBundle={}",
+                    bundleSymbolicName, versionOnServer, versionInBundle);
             return false;
         }
     }
-    
-    /** Install a list of bundles supplied as Files */
-    public void installBundles(List<File> toInstall, boolean startBundles) 
throws Exception {
+
+    /**
+     * Install a list of bundles supplied as Files
+     * @param toInstall
+     * @param startBundles
+     * @throws Exception
+     */
+    public void installBundles(List<File> toInstall, boolean startBundles) 
throws ClientException, IOException, InterruptedException {
         for(File f : toInstall) {
-            final String bundleSymbolicName = getBundleSymbolicName(f);
+            final String bundleSymbolicName = 
OsgiConsoleClient.getBundleSymbolicName(f);
             if (isInstalled(f)) {
                 if (f.getName().contains("SNAPSHOT")) {
                     log.info("Reinstalling (due to SNAPSHOT version): {}", 
bundleSymbolicName);
-                    webconsoleClient.uninstallBundle(bundleSymbolicName, f);
+                    osgiConsoleClient.uninstallBundle(bundleSymbolicName);
                 } else if (!isInstalledWithSameVersion(f)) {
                     log.info("Reinstalling (due to version mismatch): {}", 
bundleSymbolicName);
-                    webconsoleClient.uninstallBundle(bundleSymbolicName, f);
+                    osgiConsoleClient.uninstallBundle(bundleSymbolicName);
                 } else {
                     log.info("Not reinstalling: {}", bundleSymbolicName);
                     continue;
                 }
             }
-            webconsoleClient.installBundle(f, startBundles);
+            osgiConsoleClient.installBundle(f, startBundles);
             log.info("Installed: {}", bundleSymbolicName);
         }
-        
+
         // ensure that bundles are re-wired esp. if an existing bundle was 
updated
-        webconsoleClient.refreshPackages();
+        osgiConsoleClient.refreshPackages();
 
         log.info("{} additional bundles installed", toInstall.size());
     }
-    
-    /** Uninstall a list of bundles supplied as Files */
-    public void uninstallBundles(List<File> toUninstall) throws Exception {
+
+    /**
+     * Uninstall a list of bundles supplied as Files
+     * @param toUninstall
+     * @throws ClientException
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    public void uninstallBundles(List<File> toUninstall) throws 
ClientException, IOException, InterruptedException {
         for(File f : toUninstall) {
-            final String bundleSymbolicName = getBundleSymbolicName(f);
+            final String bundleSymbolicName = 
OsgiConsoleClient.getBundleSymbolicName(f);
             if (isInstalled(f)) {
                 log.info("Uninstalling bundle: {}", bundleSymbolicName);
-                webconsoleClient.uninstallBundle(bundleSymbolicName, f);
+                osgiConsoleClient.uninstallBundle(bundleSymbolicName);
             } else {
                 log.info("Could not uninstall: {} as it never was installed", 
bundleSymbolicName);
             }
         }
-        
+
         // ensure that bundles are re-wired esp. if an existing bundle was 
updated
-        webconsoleClient.refreshPackages();
+        osgiConsoleClient.refreshPackages();
 
         log.info("{} additional bundles uninstalled", toUninstall.size());
     }
-    
-    /** Wait for all bundles specified in symbolicNames list to be installed 
in the
-     *  remote web console.
-     */
-    public void waitForBundlesInstalled(List<String> symbolicNames, int 
timeoutSeconds) throws Exception {
-        log.info("Checking that bundles are installed (timeout {} seconds): 
{}", timeoutSeconds, symbolicNames);
-        for(String symbolicName : symbolicNames) {
-            webconsoleClient.checkBundleInstalled(symbolicName, 
timeoutSeconds);
-        }
+
+
+    /**
+     * Wait for all bundles specified in symbolicNames list to be installed in 
the OSGi web console.
+     * @param symbolicNames the list of names for the bundles
+     * @param timeoutSeconds how many seconds to wait
+     * @return
+     * @throws Exception
+     */
+    public boolean waitForBundlesInstalled(List<String> symbolicNames, int 
timeoutSeconds) throws ClientException, InterruptedException {
+        log.info("Checking that the following bundles are installed (timeout 
{} seconds): {}", timeoutSeconds, symbolicNames);
+        for (String symbolicName : symbolicNames) {
+            boolean started = 
osgiConsoleClient.checkBundleInstalled(symbolicName, 500, 2 * timeoutSeconds);
+            if (!started) return false;
+        }
+        return true;
     }
-    
-    public void startAllBundles(List<String> symbolicNames, int 
timeoutSeconds) throws Exception {
+
+    /**
+     * Start all the bundles in a {{List}}
+     * @param symbolicNames the list of bundles to start
+     * @param timeoutSeconds number of seconds until it times out
+     * @throws ClientException
+     * @throws InterruptedException
+     */
+    public void startAllBundles(final List<String> symbolicNames, int 
timeoutSeconds) throws ClientException, InterruptedException {
         log.info("Starting bundles (timeout {} seconds): {}", timeoutSeconds, 
symbolicNames);
-        
-        final long timeout = System.currentTimeMillis() + timeoutSeconds * 
1000L;
-        final List<String> toStart = new LinkedList<String>();
-        while(System.currentTimeMillis() < timeout) {
-            toStart.clear();
-            for(String name : symbolicNames) {
-                final String state = webconsoleClient.getBundleState(name);
-                if(!state.equalsIgnoreCase(ACTIVE_STATE)) {
-                    toStart.add(name);
-                    break;
+        class StartAllBundlesPoller extends AbstractPoller {
+            private ClientException exception;
+            public StartAllBundlesPoller(List<String> symbolicNames, long 
waitInterval, long waitCount) {
+                super(waitInterval, waitCount);
+            }
+
+            @Override
+            public boolean call() {
+                for (String bundle : symbolicNames) {
+                    final String state;
+                    try {
+                        state = osgiConsoleClient.getBundleState(bundle);
+                        if (!state.equalsIgnoreCase(ACTIVE_STATE)) {
+                            osgiConsoleClient.startBundle(bundle);
+                        }
+                    } catch (ClientException e) {
+                        this.exception = e;
+                        return false;
+                    }
+                }
+                return true;
+            }
+
+            @Override
+            public boolean condition() {
+                for (String bundle : symbolicNames) {
+                    final String state;
+                    try {
+                        state = osgiConsoleClient.getBundleState(bundle);
+                        if (!state.equalsIgnoreCase(ACTIVE_STATE)) {
+                            return false;
+                        }
+                    } catch (ClientException e) {
+                        this.exception = e;
+                        return false;
+                    }
                 }
+                return true;
+            }
+
+            public ClientException getException() {
+                return exception;
             }
-            
-            if(toStart.isEmpty()) {
-                log.info("Ok - all bundles are in the {} state", ACTIVE_STATE);
-                break;
-            }
-            
-            for(String name : toStart) {
-                webconsoleClient.startBundle(name);
-            }
-            
-            Thread.sleep(500L);
-        }
-        
-        if(!toStart.isEmpty()) {
-            throw new Exception("Some bundles did not start: " + toStart);
-        }
-    }
-    
-    public String getBundleSymbolicName(File bundleFile) throws IOException {
-        String name = null;
-        final JarInputStream jis = new JarInputStream(new 
FileInputStream(bundleFile));
-        try {
-            final Manifest m = jis.getManifest();
-            if (m == null) {
-                throw new IOException("Manifest is null in " + 
bundleFile.getAbsolutePath());
-            }
-            name = 
m.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
-        } finally {
-            jis.close();
-        }
-        return name;
-    }
-    
-    public String getBundleVersion(File bundleFile) throws IOException {
-        String version = null;
-        final JarInputStream jis = new JarInputStream(new 
FileInputStream(bundleFile));
-        try {
-            final Manifest m = jis.getManifest();
-            if(m == null) {
-                throw new IOException("Manifest is null in " + 
bundleFile.getAbsolutePath());
-            }
-            version = m.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
-        } finally {
-            jis.close();
         }
-        return version;
+        StartAllBundlesPoller poller = new 
StartAllBundlesPoller(symbolicNames, 1000, timeoutSeconds);
+        if (!poller.callUntilCondition()) {
+            throw new ClientException("Some bundles did not start or timed 
out", poller.getException());
+        }
+
     }
+
+
+
+
 }
\ No newline at end of file

Modified: 
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/OsgiConsoleClient.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/OsgiConsoleClient.java?rev=1743676&r1=1743675&r2=1743676&view=diff
==============================================================================
--- 
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/OsgiConsoleClient.java
 (original)
+++ 
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/osgi/OsgiConsoleClient.java
 Fri May 13 14:02:03 2016
@@ -18,7 +18,11 @@
 package org.apache.sling.testing.clients.osgi;
 
 import org.apache.http.Header;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.sling.commons.json.JSONArray;
+import org.apache.sling.commons.json.JSONException;
+import org.apache.sling.commons.json.JSONObject;
 import org.apache.sling.testing.clients.ClientException;
 import org.apache.sling.testing.clients.SlingHttpResponse;
 import org.apache.sling.testing.clients.util.JsonUtils;
@@ -27,18 +31,27 @@ import org.apache.sling.testing.clients.
 import org.apache.sling.testing.clients.SlingClientConfig;
 import org.apache.sling.testing.clients.util.FormEntityBuilder;
 import org.apache.sling.testing.clients.util.HttpUtils;
+import org.apache.sling.testing.clients.util.poller.PathPoller;
 import org.codehaus.jackson.JsonNode;
+import org.osgi.framework.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.net.URI;
 import java.util.*;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
 
 import static org.apache.http.HttpStatus.SC_MOVED_TEMPORARILY;
 import static org.apache.http.HttpStatus.SC_OK;
 
 /**
  * A client that wraps the Felix OSGi Web Console REST API calls.
+ * @see <a 
href=http://felix.apache.org/documentation/subprojects/apache-felix-web-console/web-console-restful-api.html>
+ *     Web Console RESTful API</a>
  */
 public class OsgiConsoleClient extends SlingClient {
 
@@ -63,6 +76,12 @@ public class OsgiConsoleClient extends S
      */
     private final String URL_COMPONENTS = CONSOLE_ROOT_URL + "/components";
 
+
+    public static final String JSON_KEY_ID = "id";
+    public static final String JSON_KEY_VERSION = "version";
+    public static final String JSON_KEY_DATA = "data";
+    public static final String JSON_KEY_STATE = "state";
+
     /**
      * Default constructor. Simply calls {@link SlingClient#SlingClient(URI, 
String, String)}
      *
@@ -141,6 +160,10 @@ public class OsgiConsoleClient extends S
         return new 
ComponentInfo(JsonUtils.getJsonNodeFromString(resp.getContent()));
     }
 
+    //
+    // OSGi configurations
+    //
+
     /**
      * Returns a map of all properties set for the config referenced by the 
PID, where the map keys
      * are the property names.
@@ -276,16 +299,282 @@ public class OsgiConsoleClient extends S
      *
      * @param pid pid
      * @param expectedStatus expected response status
+     * @return the sling response
      * @throws ClientException if the response status does not match any of 
the expectedStatus
      */
-    public void deleteConfiguration(String pid, int... expectedStatus) throws 
ClientException {
+    public SlingHttpResponse deleteConfiguration(String pid, int... 
expectedStatus) throws ClientException {
         FormEntityBuilder builder = FormEntityBuilder.create();
         builder.addParameter("apply", "1");
         builder.addParameter("delete", "1");
         // make the request
         SlingHttpResponse resp = this.doPost(URL_CONFIGURATION + "/" + pid, 
builder.build());
-        // check the returned status         
+        // check the returned status
         HttpUtils.verifyHttpStatus(resp, HttpUtils.getExpectedStatus(200, 
expectedStatus));
+        return resp;
+    }
+
+    //
+    // Bundles
+    //
+
+    /**
+     * Uninstall a bundle
+     * @param symbolicName
+     * @return the sling response
+     * @throws ClientException
+     */
+    public SlingHttpResponse uninstallBundle(String symbolicName) throws 
ClientException {
+        final long bundleId = getBundleId(symbolicName);
+        LOG.info("Uninstalling bundle {} with bundleId {}", symbolicName, 
bundleId);
+        FormEntityBuilder builder = FormEntityBuilder.create();
+        builder.addParameter("action", "uninstall");
+        return this.doPost(getBundlePath(symbolicName), builder.build(), 200);
+    }
+
+    /**
+     * Install a bundle using the Felix webconsole HTTP interface
+     * @param f the bundle file
+     * @param startBundle whether to start the bundle or not
+     * @return the sling response
+     * @throws ClientException
+     */
+    public SlingHttpResponse installBundle(File f, boolean startBundle) throws 
ClientException {
+        return installBundle(f, startBundle, 0);
+    }
+
+    /**
+     * Install a bundle using the Felix webconsole HTTP interface, with a 
specific start level
+     * @param f
+     * @param startBundle
+     * @param startLevel
+     * @return the sling response
+     * @throws ClientException
+     */
+    public SlingHttpResponse installBundle(File f, boolean startBundle, int 
startLevel) throws ClientException {
+        // Setup request for Felix Webconsole bundle install
+        MultipartEntityBuilder builder = MultipartEntityBuilder.create()
+                .addTextBody("action", "install")
+                .addBinaryBody("bundlefile", f);
+        if (startBundle) {
+            builder.addTextBody("bundlestart", "true");
+        }
+        if (startLevel > 0) {
+            builder.addTextBody("bundlestartlevel", 
String.valueOf(startLevel));
+            LOG.info("Installing bundle {} at start level {}", f.getName(), 
startLevel);
+        } else {
+            LOG.info("Installing bundle {} at default start level", 
f.getName());
+        }
+
+        return this.doPost(URL_BUNDLES, builder.build(), 302);
+
+    }
+
+    /**
+     * Install a bundle using the Felix webconsole HTTP interface and wait for 
it to be installed
+     * @param f the bundle file
+     * @param startBundle whether to start the bundle or not
+     * @param startLevel the start level of the bundle. negative values mean 
default start level
+     * @param waitTime how long to wait between retries of checking the bundle
+     * @param retries how many times to check for the bundle to be installed, 
until giving up
+     * @return true if the bundle was successfully installed, false otherwise
+     * @throws ClientException
+     */
+    public boolean installBundleWithRetry(File f, boolean startBundle, int 
startLevel, int waitTime, int retries)
+            throws ClientException, InterruptedException {
+        installBundle(f, startBundle, startLevel);
+        try {
+            return 
this.checkBundleInstalled(OsgiConsoleClient.getBundleSymbolicName(f), waitTime, 
retries);
+        } catch (IOException e) {
+            throw new ClientException("Cannot get bundle symbolic name", e);
+        }
+    }
+
+    /**
+     * Check that specified bundle is installed and retries every {{waitTime}} 
milliseconds, until the
+     * bundle is installed or the number of retries was reached
+     * @param symbolicName the name of the bundle
+     * @param waitTime How many milliseconds to wait between retries
+     * @param retries the number of retries
+     * @return true if the bundle was installed until the retries stop, false 
otherwise
+     * @throws InterruptedException
+     */
+    public boolean checkBundleInstalled(String symbolicName, int waitTime, int 
retries) throws InterruptedException {
+        final String path = getBundlePath(symbolicName, ".json");
+        return new PathPoller(this, path, waitTime, retries).callAndWait();
+    }
+
+    /**
+     * Get the id of the bundle
+     * @param symbolicName
+     * @return
+     * @throws Exception
+     */
+    public long getBundleId(String symbolicName) throws ClientException {
+        final JSONObject bundle = getBundleData(symbolicName);
+        try {
+            return bundle.getLong(JSON_KEY_ID);
+        } catch (JSONException e) {
+            throw new ClientException("Cannot get id from json", e);
+        }
+    }
+
+    /**
+     * Get the version of the bundle
+     * @param symbolicName
+     * @return
+     * @throws ClientException
+     */
+    public String getBundleVersion(String symbolicName) throws ClientException 
{
+        final JSONObject bundle = getBundleData(symbolicName);
+        try {
+            return bundle.getString(JSON_KEY_VERSION);
+        } catch (JSONException e) {
+            throw new ClientException("Cannot get version from json", e);
+        }
+    }
+
+    /**
+     * Get the state of the bundle
+     * @param symbolicName
+     * @return
+     * @throws Exception
+     */
+    public String getBundleState(String symbolicName) throws ClientException {
+        final JSONObject bundle = getBundleData(symbolicName);
+        try {
+            return bundle.getString(JSON_KEY_STATE);
+        } catch (JSONException e) {
+            throw new ClientException("Cannot get state from json", e);
+        }
+    }
+
+    /**
+     * Starts a bundle
+     * @param symbolicName the name of the bundle
+     * @throws ClientException
+     */
+    public void startBundle(String symbolicName) throws ClientException {
+        // To start the bundle we POST action=start to its URL
+        final String path = getBundlePath(symbolicName);
+        LOG.info("Starting bundle {} via {}", symbolicName, path);
+        this.doPost(path, FormEntityBuilder.create().addParameter("action", 
"start").build(), SC_OK);
+    }
+
+    /**
+     * Starts a bundle and waits for it to be started
+     * @param symbolicName the name of the bundle
+     * @param waitTime How many milliseconds to wait between retries
+     * @param retries the number of retries
+     * @throws ClientException, InterruptedException
+     */
+    public void startBundlewithWait(String symbolicName, int waitTime, int 
retries)
+            throws ClientException, InterruptedException {
+        // start a bundle
+        startBundle(symbolicName);
+        // wait for it to be in the started state
+        checkBundleInstalled(symbolicName, waitTime, retries);
+    }
+
+    /**
+     * Calls PackageAdmin.refreshPackages to force re-wiring of all the 
bundles.
+     * @throws ClientException
+     */
+    public void refreshPackages() throws ClientException {
+        LOG.info("Refreshing packages.");
+        FormEntityBuilder builder = FormEntityBuilder.create();
+        builder.addParameter("action", "refreshPackages");
+        this.doPost(URL_BUNDLES, builder.build(), 200);
+    }
+
+
+    //
+    // private methods
+    //
+
+    private String getBundlePath(String symbolicName, String extension) {
+        return getBundlePath(symbolicName) + extension;
+    }
+
+    private String getBundlePath(String symbolicName) {
+        return URL_BUNDLES + "/" + symbolicName;
+    }
+
+    private JSONObject getBundleData(String symbolicName) throws 
ClientException {
+        // This returns a data structure like
+        // {"status":"Bundle information: 173 bundles in total - all 173 
bundles active.","s":[173,171,2,0,0],"data":
+        //  [
+        //      {"id":0,"name":"System 
Bundle","fragment":false,"stateRaw":32,"state":"Active","version":"3.0.7","symbolicName":"org.apache.felix.framework","category":""},
+        //  ]}
+        final String path = getBundlePath(symbolicName, ".json");
+        final String content = this.doGet(path, SC_OK).getContent();
+
+        try {
+            final JSONObject root = new JSONObject(content);
+
+            if (!root.has(JSON_KEY_DATA)) {
+                throw new ClientException(path + " does not provide '" + 
JSON_KEY_DATA + "' element, JSON content=" + content);
+            }
+
+            final JSONArray data = root.getJSONArray(JSON_KEY_DATA);
+            if (data.length() < 1) {
+                throw new ClientException(path + "." + JSON_KEY_DATA + " is 
empty, JSON content=" + content);
+            }
+
+            final JSONObject bundle = data.getJSONObject(0);
+            if (!bundle.has(JSON_KEY_STATE)) {
+                throw new ClientException(path + ".data[0].state missing, JSON 
content=" + content);
+            }
+
+            return bundle;
+        } catch (JSONException e) {
+            throw new ClientException("Cannot get json", e);
+        }
+    }
+
+    //
+    // static methods
+    //
+
+    /**
+     * Get the symbolic name from a bundle file
+     * @param bundleFile
+     * @return
+     * @throws IOException
+     */
+    public static String getBundleSymbolicName(File bundleFile) throws 
IOException {
+        String name = null;
+        final JarInputStream jis = new JarInputStream(new 
FileInputStream(bundleFile));
+        try {
+            final Manifest m = jis.getManifest();
+            if (m == null) {
+                throw new IOException("Manifest is null in " + 
bundleFile.getAbsolutePath());
+            }
+            name = 
m.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
+        } finally {
+            jis.close();
+        }
+        return name;
+    }
+
+    /**
+     * Get the version form a bundle file
+     * @param bundleFile
+     * @return
+     * @throws IOException
+     */
+    public static String getBundleVersionFromFile(File bundleFile) throws 
IOException {
+        String version = null;
+        final JarInputStream jis = new JarInputStream(new 
FileInputStream(bundleFile));
+        try {
+            final Manifest m = jis.getManifest();
+            if(m == null) {
+                throw new IOException("Manifest is null in " + 
bundleFile.getAbsolutePath());
+            }
+            version = m.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
+        } finally {
+            jis.close();
+        }
+        return version;
     }
 
 

Added: 
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/poller/PathPoller.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/poller/PathPoller.java?rev=1743676&view=auto
==============================================================================
--- 
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/poller/PathPoller.java
 (added)
+++ 
sling/trunk/testing/http/clients/src/main/java/org/apache/sling/testing/clients/util/poller/PathPoller.java
 Fri May 13 14:02:03 2016
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * 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
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * 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.testing.clients.util.poller;
+
+import org.apache.sling.testing.clients.AbstractSlingClient;
+import org.apache.sling.testing.clients.ClientException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Allows polling for a resource
+ */
+public class PathPoller extends AbstractPoller {
+    private static final Logger LOG = 
LoggerFactory.getLogger(PathPoller.class);
+    private final AbstractSlingClient client;
+    private final String path;
+    private final int[] expectedStatus;
+    private Exception exception;
+
+    public PathPoller(AbstractSlingClient client, String path, long 
waitInterval, long waitCount, int... expectedStatus) {
+        super(waitInterval, waitCount);
+        this.client = client;
+        this.path = path;
+        this.expectedStatus = expectedStatus;
+    }
+
+
+    @Override
+    public boolean call() {
+        return true;
+    }
+
+    @Override
+    public boolean condition() {
+        try {
+            client.doGet(path, expectedStatus);
+        } catch (ClientException e) {
+            LOG.warn("Get on {} failed: {}", path, e);
+            this.exception = e;
+            return false;
+        }
+        return true;
+    }
+
+    public Exception getException() {
+        return exception;
+    }
+}


Reply via email to