| /* |
| * 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.testing.clients.osgi; |
| |
| import org.apache.sling.testing.clients.ClientException; |
| import org.apache.sling.testing.clients.exceptions.TestValidationException; |
| import org.apache.sling.testing.clients.util.poller.Polling; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.List; |
| import java.util.concurrent.TimeoutException; |
| |
| |
| /** |
| * Utility for installing and starting additional bundles for testing |
| */ |
| public class BundlesInstaller { |
| private final Logger log = LoggerFactory.getLogger(getClass()); |
| private final OsgiConsoleClient osgiConsoleClient; |
| public static final String ACTIVE_STATE = "active"; |
| |
| public BundlesInstaller(OsgiConsoleClient cc) { |
| osgiConsoleClient = cc; |
| } |
| |
| /** |
| * Checks if a bundle is installed or not. Does not retry. |
| * @param bundleFile bundle file |
| * @return true if the bundle is installed |
| * @throws ClientException if the state of the bundle could not be determined |
| */ |
| public boolean isInstalled(File bundleFile) throws ClientException { |
| String bundleSymbolicName = ""; |
| try { |
| bundleSymbolicName = OsgiConsoleClient.getBundleSymbolicName(bundleFile); |
| log.debug("Checking if installed: " + bundleSymbolicName); |
| |
| osgiConsoleClient.getBundleState(bundleSymbolicName); |
| log.debug("Already installed: " + bundleSymbolicName); |
| return true; |
| } catch (ClientException e) { |
| log.debug("Not yet installed: " + bundleSymbolicName); |
| return false; |
| } catch (IOException e) { |
| log.debug("Failed to retrieve bundle symbolic name from file. ", e); |
| throw new TestValidationException("Failed to retrieve bundle symbolic name from file. ", e); |
| } |
| } |
| |
| /** |
| * Check if the installed version matches the one of the bundle (file) |
| * @param bundleFile bundle file |
| * @return true if the bundle is installed and has the same version |
| * @throws ClientException if the installed version cannot be retrieved |
| * @throws IOException if the file version cannot be read |
| */ |
| 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.warn("Installed bundle doesn't match: {}, versionOnServer={}, versionInBundle={}", |
| bundleSymbolicName, versionOnServer, versionInBundle); |
| return false; |
| } |
| } |
| |
| /** |
| * Install a list of bundles supplied as Files |
| * @param toInstall list ob bundles to install |
| * @param startBundles whether to start the bundles |
| * @throws ClientException if an error occurs during installation |
| * @throws IOException if reading the file fails |
| */ |
| public void installBundles(List<File> toInstall, boolean startBundles) throws ClientException, IOException { |
| for(File f : toInstall) { |
| final String bundleSymbolicName = OsgiConsoleClient.getBundleSymbolicName(f); |
| if (isInstalled(f)) { |
| if (f.getName().contains("SNAPSHOT")) { |
| log.info("Reinstalling (due to SNAPSHOT version): {}", bundleSymbolicName); |
| osgiConsoleClient.uninstallBundle(bundleSymbolicName); |
| } else if (!isInstalledWithSameVersion(f)) { |
| log.info("Reinstalling (due to version mismatch): {}", bundleSymbolicName); |
| osgiConsoleClient.uninstallBundle(bundleSymbolicName); |
| } else { |
| log.info("Not reinstalling: {}", bundleSymbolicName); |
| continue; |
| } |
| } |
| osgiConsoleClient.installBundle(f, startBundles); |
| log.info("Installed: {}", bundleSymbolicName); |
| } |
| |
| // ensure that bundles are re-wired esp. if an existing bundle was updated |
| osgiConsoleClient.refreshPackages(); |
| |
| log.info("{} additional bundles installed", toInstall.size()); |
| } |
| |
| /** |
| * Uninstall a list of bundles supplied as Files |
| * @param toUninstall bundles to uninstall |
| * @throws ClientException if one of the requests failed |
| * @throws IOException if the files cannot be read from disk |
| */ |
| public void uninstallBundles(List<File> toUninstall) throws ClientException, IOException { |
| for(File f : toUninstall) { |
| final String bundleSymbolicName = OsgiConsoleClient.getBundleSymbolicName(f); |
| if (isInstalled(f)) { |
| log.info("Uninstalling bundle: {}", bundleSymbolicName); |
| 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 |
| osgiConsoleClient.refreshPackages(); |
| |
| log.info("{} additional bundles uninstalled", toUninstall.size()); |
| } |
| |
| |
| /** |
| * Wait for all bundles specified in symbolicNames list to be installed in the OSGi web console. |
| * @deprecated use {@link #waitBundlesInstalled(List, long)} |
| * @param symbolicNames the list of names for the bundles |
| * @param timeoutSeconds how many seconds to wait |
| * @throws ClientException if something went wrong |
| * @throws InterruptedException if interrupted |
| * @return true if all the bundles were installed |
| */ |
| @Deprecated |
| 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; |
| } |
| |
| /** |
| * Wait for multiple bundles to be installed in the OSGi web console. |
| * @param symbolicNames the list bundles to be checked |
| * @param timeout max total time to wait for all bundles, in ms, before throwing {@code TimeoutException} |
| * @throws TimeoutException if the timeout was reached before all the bundles were installed |
| * @throws InterruptedException to mark this operation as "waiting", callers should rethrow it |
| */ |
| public void waitBundlesInstalled(List<String> symbolicNames, long timeout) |
| throws InterruptedException, TimeoutException { |
| log.info("Checking that the following bundles are installed (timeout {} ms): {}", timeout, symbolicNames); |
| long start = System.currentTimeMillis(); |
| for (String symbolicName : symbolicNames) { |
| osgiConsoleClient.waitBundleInstalled(symbolicName, timeout, 500); |
| |
| if (System.currentTimeMillis() > start + timeout) { |
| throw new TimeoutException("Waiting for bundles did not finish in " + timeout + " ms."); |
| } |
| } |
| } |
| |
| /** |
| * Start all the bundles in a {{List}} |
| * @param symbolicNames the list of bundles to start |
| * @param timeout total max time to wait for all the bundles, in ms |
| * @throws TimeoutException if the timeout is reached before all the bundles are started |
| * @throws InterruptedException to mark this operation as "waiting", callers should rethrow it |
| */ |
| public void startAllBundles(final List<String> symbolicNames, int timeout) throws InterruptedException, TimeoutException { |
| log.info("Starting bundles (timeout {} seconds): {}", timeout, symbolicNames); |
| |
| Polling p = new Polling() { |
| @Override |
| public Boolean call() throws Exception { |
| boolean allActive = true; |
| for (String bundle : symbolicNames) { |
| String state = osgiConsoleClient.getBundleState(bundle); |
| if (!state.equalsIgnoreCase(ACTIVE_STATE)) { |
| osgiConsoleClient.startBundle(bundle); |
| allActive = false; |
| } |
| } |
| return allActive; |
| } |
| }; |
| |
| p.poll(timeout, 500); |
| } |
| } |