/** * 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.aries.jmx.framework; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.management.openmbean.CompositeData; import org.apache.aries.jmx.codec.BatchActionResult; import org.apache.aries.jmx.codec.BatchInstallResult; import org.apache.aries.jmx.codec.BatchResolveResult; import org.apache.aries.jmx.util.FrameworkUtils; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkEvent; import org.osgi.framework.FrameworkListener; import org.osgi.framework.wiring.FrameworkWiring; import org.osgi.jmx.framework.FrameworkMBean; import org.osgi.service.packageadmin.PackageAdmin; import org.osgi.service.startlevel.StartLevel; /** * <p> * <tt>Framework</tt> represents {@link FrameworkMBean} implementation. * </p> * @see FrameworkMBean * * @version $Rev$ $Date$ */ public class Framework implements FrameworkMBean { private StartLevel startLevel; private PackageAdmin packageAdmin; private BundleContext context; /** * Constructs new FrameworkMBean. * * @param context bundle context of jmx bundle. * @param startLevel @see {@link StartLevel} service reference. * @param packageAdmin @see {@link PackageAdmin} service reference. */ public Framework(BundleContext context, StartLevel startLevel, PackageAdmin packageAdmin) { this.context = context; this.startLevel = startLevel; this.packageAdmin = packageAdmin; } /** * @see org.osgi.jmx.framework.FrameworkMBean#getDependencyClosureBundles(long[]) */ public long[] getDependencyClosure(long[] bundles) throws IOException { FrameworkWiring fw = context.getBundle(0).adapt(FrameworkWiring.class); List<Bundle> bl = new ArrayList<Bundle>(); for (int i=0; i < bundles.length; i++) { bl.add(context.getBundle(bundles[i])); } Collection<Bundle> rc = fw.getDependencyClosure(bl); Iterator<Bundle> it = rc.iterator(); long[] result = new long[rc.size()]; for (int i = 0; i < result.length; i++) { result[i] = it.next().getBundleId(); } return result; } /** * @see org.osgi.jmx.framework.FrameworkMBean#getFrameworkStartLevel() */ public int getFrameworkStartLevel() throws IOException { return startLevel.getStartLevel(); } /** * @see org.osgi.jmx.framework.FrameworkMBean#getInitialBundleStartLevel() */ public int getInitialBundleStartLevel() throws IOException { return startLevel.getInitialBundleStartLevel(); } /** * @see org.osgi.jmx.framework.FrameworkMBean#getProperty(java.lang.String) */ public String getProperty(String key) { return context.getProperty(key); } /** * @see org.osgi.jmx.framework.FrameworkMBean#getRemovalPendingBundles() */ public long[] getRemovalPendingBundles() throws IOException { FrameworkWiring fw = context.getBundle(0).adapt(FrameworkWiring.class); Collection<Bundle> rc = fw.getRemovalPendingBundles(); Iterator<Bundle> it = rc.iterator(); long[] result = new long[rc.size()]; for (int i = 0; i < result.length; i++) { result[i] = it.next().getBundleId(); } return result; } /** * @see org.osgi.jmx.framework.FrameworkMBean#installBundle(java.lang.String) */ public long installBundle(String location) throws IOException { try { Bundle bundle = context.installBundle(location); return bundle.getBundleId(); } catch (Exception e) { IOException ioex = new IOException("Installation of a bundle with location " + location + " failed with the message: " + e.getMessage()); ioex.initCause(e); throw ioex; } } /** * @see org.osgi.jmx.framework.FrameworkMBean#installBundleFromURL(String, String) */ public long installBundleFromURL(String location, String url) throws IOException { InputStream inputStream = null; try { inputStream = createStream(url); Bundle bundle = context.installBundle(location, inputStream); return bundle.getBundleId(); } catch (Exception e) { IOException ioex = new IOException("Installation of a bundle with location " + location + " failed with the message: " + e.getMessage()); ioex.initCause(e); throw ioex; } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException ioe) { } } } } public InputStream createStream(String url) throws IOException { return new URL(url).openStream(); } /** * @see org.osgi.jmx.framework.FrameworkMBean#installBundles(java.lang.String[]) */ public CompositeData installBundles(String[] locations) throws IOException { if(locations == null){ return new BatchInstallResult("Failed to install bundles locations can't be null").toCompositeData(); } long[] ids = new long[locations.length]; for (int i = 0; i < locations.length; i++) { try { long id = installBundle(locations[i]); ids[i] = id; } catch (Throwable t) { long[] completed = new long[i]; System.arraycopy(ids, 0, completed, 0, i); String[] remaining = new String[locations.length - i - 1]; System.arraycopy(locations, i + 1, remaining, 0, remaining.length); return new BatchInstallResult(completed, t.toString(), remaining, locations[i]).toCompositeData(); } } return new BatchInstallResult(ids).toCompositeData(); } /** * @see org.osgi.jmx.framework.FrameworkMBean#installBundlesFromURL(String[], String[]) */ public CompositeData installBundlesFromURL(String[] locations, String[] urls) throws IOException { if(locations == null || urls == null){ return new BatchInstallResult("Failed to install bundles arguments can't be null").toCompositeData(); } if(locations.length != urls.length){ return new BatchInstallResult("Failed to install bundles size of arguments should be same").toCompositeData(); } long[] ids = new long[locations.length]; for (int i = 0; i < locations.length; i++) { try { long id = installBundleFromURL(locations[i], urls[i]); ids[i] = id; } catch (Throwable t) { long[] completed = new long[i]; System.arraycopy(ids, 0, completed, 0, i); String[] remaining = new String[locations.length - i - 1]; System.arraycopy(locations, i + 1, remaining, 0, remaining.length); return new BatchInstallResult(completed, t.toString(), remaining, locations[i]).toCompositeData(); } } return new BatchInstallResult(ids).toCompositeData(); } /** * @see org.osgi.jmx.framework.FrameworkMBean#refreshBundle(long) */ public void refreshBundle(long bundleIdentifier) throws IOException { Bundle bundle = FrameworkUtils.resolveBundle(context, bundleIdentifier); packageAdmin.refreshPackages(new Bundle[] { bundle }); } /** * @see org.osgi.jmx.framework.FrameworkMBean#refreshBundleAndWait(long) */ public boolean refreshBundleAndWait(long bundleIdentifier) throws IOException { Bundle[] bundleArray = new Bundle[1]; refreshBundlesAndWait(new long[] {bundleIdentifier}, bundleArray); return isResolved(bundleArray[0].getState()); } /** * @see org.osgi.jmx.framework.FrameworkMBean#refreshBundles(long[]) */ public void refreshBundles(long[] bundleIdentifiers) throws IOException { Bundle[] bundles = null; if(bundleIdentifiers != null) { bundles = new Bundle[bundleIdentifiers.length]; for (int i = 0; i < bundleIdentifiers.length; i++) { try { bundles[i] = FrameworkUtils.resolveBundle(context, bundleIdentifiers[i]); } catch (Exception e) { IOException ex = new IOException("Unable to find bundle with id " + bundleIdentifiers[i]); ex.initCause(e); throw ex; } } } packageAdmin.refreshPackages(bundles); } /** * @see org.osgi.jmx.framework.FrameworkMBean#refreshBundlesAndWait(long[]) */ public CompositeData refreshBundlesAndWait(long[] bundleIdentifiers) throws IOException { Bundle [] bundles = bundleIdentifiers != null ? new Bundle[bundleIdentifiers.length] : null; refreshBundlesAndWait(bundleIdentifiers, bundles); return constructResolveResult(bundles); } private void refreshBundlesAndWait(long[] bundleIdentifiers, Bundle[] bundles) throws IOException { final CountDownLatch latch = new CountDownLatch(1); FrameworkListener listener = new FrameworkListener() { public void frameworkEvent(FrameworkEvent event) { if (FrameworkEvent.PACKAGES_REFRESHED == event.getType()) { latch.countDown(); } } }; try { context.addFrameworkListener(listener); try { if (bundles != null) { for (int i=0; i < bundleIdentifiers.length; i++) { bundles[i] = FrameworkUtils.resolveBundle(context, bundleIdentifiers[i]); } } packageAdmin.refreshPackages(bundles); if (latch.await(30, TimeUnit.SECONDS)) return; else throw new IOException("Refresh operation timed out"); } catch (InterruptedException e) { IOException ex = new IOException(); ex.initCause(e); throw ex; } } finally { context.removeFrameworkListener(listener); } } private CompositeData constructResolveResult(Bundle[] bundles) { if (bundles == null) bundles = context.getBundles(); boolean result = true; List<Long> successList = new ArrayList<Long>(); for (Bundle bundle : bundles) { int state = bundle.getState(); if (isResolved(state)) { successList.add(bundle.getBundleId()); } else result = false; } return new BatchResolveResult(result, successList.toArray(new Long[] {})).toCompositeData(); } private boolean isResolved(int state) { return (state & (Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE)) > 0; } /** * @see org.osgi.jmx.framework.FrameworkMBean#resolveBundle(long) */ public boolean resolveBundle(long bundleIdentifier) throws IOException { Bundle bundle = FrameworkUtils.resolveBundle(context, bundleIdentifier); return packageAdmin.resolveBundles(new Bundle[] { bundle }); } /** * @see org.osgi.jmx.framework.FrameworkMBean#resolveBundles(long[]) */ public boolean resolveBundles(long[] bundleIdentifiers) throws IOException { Bundle[] bundles = null; if (bundleIdentifiers != null) bundles = new Bundle[bundleIdentifiers.length]; return resolveBundles(bundleIdentifiers, bundles); } private boolean resolveBundles(long[] bundleIdentifiers, Bundle[] bundles) throws IOException { if (bundleIdentifiers != null) { for (int i = 0; i < bundleIdentifiers.length; i++) { try { bundles[i] = FrameworkUtils.resolveBundle(context, bundleIdentifiers[i]); } catch (Exception e) { IOException ex = new IOException("Unable to find bundle with id " + bundleIdentifiers[i]); ex.initCause(e); throw ex; } } } return packageAdmin.resolveBundles(bundles); } public CompositeData resolve(long[] bundleIdentifiers) throws IOException { Bundle[] bundles = null; if (bundleIdentifiers != null) bundles = new Bundle[bundleIdentifiers.length]; resolveBundles(bundleIdentifiers, bundles); return constructResolveResult(bundles); } /** * @see org.osgi.jmx.framework.FrameworkMBean#restartFramework() */ public void restartFramework() throws IOException { Bundle bundle = FrameworkUtils.resolveBundle(context, 0); try { bundle.update(); } catch (Exception be) { IOException ioex = new IOException("Framework restart failed with message: " + be.getMessage()); ioex.initCause(be); throw ioex; } } /** * @see org.osgi.jmx.framework.FrameworkMBean#setBundleStartLevel(long, int) */ public void setBundleStartLevel(long bundleIdentifier, int newlevel) throws IOException { Bundle bundle = FrameworkUtils.resolveBundle(context, bundleIdentifier); try { startLevel.setBundleStartLevel(bundle, newlevel); } catch (IllegalArgumentException e) { IOException ioex = new IOException("Setting the start level for bundle with id " + bundle.getBundleId() + " to level " + newlevel + " failed with message: " + e.getMessage()); ioex.initCause(e); throw ioex; } } /** * @see org.osgi.jmx.framework.FrameworkMBean#setBundleStartLevels(long[], int[]) */ public CompositeData setBundleStartLevels(long[] bundleIdentifiers, int[] newlevels) throws IOException { if (bundleIdentifiers == null || newlevels == null) { return new BatchActionResult("Failed to setBundleStartLevels arguments can't be null").toCompositeData(); } if (bundleIdentifiers != null && newlevels != null && bundleIdentifiers.length != newlevels.length) { return new BatchActionResult("Failed to setBundleStartLevels size of arguments should be same").toCompositeData(); } for (int i = 0; i < bundleIdentifiers.length; i++) { try { setBundleStartLevel(bundleIdentifiers[i], newlevels[i]); } catch (Throwable t) { return createFailedBatchActionResult(bundleIdentifiers, i, t); } } return new BatchActionResult(bundleIdentifiers).toCompositeData(); } /** * @see org.osgi.jmx.framework.FrameworkMBean#setFrameworkStartLevel(int) */ public void setFrameworkStartLevel(int newlevel) throws IOException { try { startLevel.setStartLevel(newlevel); } catch (Exception e) { IOException ioex = new IOException("Setting the framework start level to " + newlevel + " failed with message: " + e.getMessage()); ioex.initCause(e); throw ioex; } } /** * @see org.osgi.jmx.framework.FrameworkMBean#setInitialBundleStartLevel(int) */ public void setInitialBundleStartLevel(int newlevel) throws IOException { try { startLevel.setInitialBundleStartLevel(newlevel); } catch (Exception e) { IOException ioex = new IOException("Setting the initial start level to " + newlevel + " failed with message: " + e.getMessage()); ioex.initCause(e); throw ioex; } } /** * @see org.osgi.jmx.framework.FrameworkMBean#shutdownFramework() */ public void shutdownFramework() throws IOException { Bundle bundle = FrameworkUtils.resolveBundle(context, 0); try { bundle.stop(); } catch (Exception be) { IOException ioex = new IOException("Stopping the framework failed with message: " + be.getMessage()); ioex.initCause(be); throw ioex; } } /** * @see org.osgi.jmx.framework.FrameworkMBean#startBundle(long) */ public void startBundle(long bundleIdentifier) throws IOException { Bundle bundle = FrameworkUtils.resolveBundle(context, bundleIdentifier); try { bundle.start(); } catch (Exception be) { IOException ioex = new IOException("Start of bundle with id " + bundleIdentifier + " failed with message: " + be.getMessage()); ioex.initCause(be); throw ioex; } } /** * @see org.osgi.jmx.framework.FrameworkMBean#startBundles(long[]) */ public CompositeData startBundles(long[] bundleIdentifiers) throws IOException { if (bundleIdentifiers == null) { return new BatchActionResult("Failed to start bundles, bundle id's can't be null").toCompositeData(); } for (int i = 0; i < bundleIdentifiers.length; i++) { try { startBundle(bundleIdentifiers[i]); } catch (Throwable t) { return createFailedBatchActionResult(bundleIdentifiers, i, t); } } return new BatchActionResult(bundleIdentifiers).toCompositeData(); } /** * @see org.osgi.jmx.framework.FrameworkMBean#stopBundle(long) */ public void stopBundle(long bundleIdentifier) throws IOException { Bundle bundle = FrameworkUtils.resolveBundle(context, bundleIdentifier); try { bundle.stop(); } catch (Exception e) { IOException ioex = new IOException("Stop of bundle with id " + bundleIdentifier + " failed with message: " + e.getMessage()); ioex.initCause(e); throw ioex; } } /** * @see org.osgi.jmx.framework.FrameworkMBean#stopBundles(long[]) */ public CompositeData stopBundles(long[] bundleIdentifiers) throws IOException { if (bundleIdentifiers == null) { return new BatchActionResult("Failed to stop bundles, bundle id's can't be null").toCompositeData(); } for (int i = 0; i < bundleIdentifiers.length; i++) { try { stopBundle(bundleIdentifiers[i]); } catch (Throwable t) { return createFailedBatchActionResult(bundleIdentifiers, i, t); } } return new BatchActionResult(bundleIdentifiers).toCompositeData(); } /** * @see org.osgi.jmx.framework.FrameworkMBean#uninstallBundle(long) */ public void uninstallBundle(long bundleIdentifier) throws IOException { Bundle bundle = FrameworkUtils.resolveBundle(context, bundleIdentifier); try { bundle.uninstall(); } catch (Exception be) { IOException ioex = new IOException("Uninstall of bundle with id " + bundleIdentifier + " failed with message: " + be.getMessage()); ioex.initCause(be); throw ioex; } } /** * @see org.osgi.jmx.framework.FrameworkMBean#uninstallBundles(long[]) */ public CompositeData uninstallBundles(long[] bundleIdentifiers) throws IOException { if (bundleIdentifiers == null) { return new BatchActionResult("Failed uninstall bundles, bundle id's can't be null").toCompositeData(); } for (int i = 0; i < bundleIdentifiers.length; i++) { try { uninstallBundle(bundleIdentifiers[i]); } catch (Throwable t) { return createFailedBatchActionResult(bundleIdentifiers, i, t); } } return new BatchActionResult(bundleIdentifiers).toCompositeData(); } /** * @see org.osgi.jmx.framework.FrameworkMBean#updateBundle(long) */ public void updateBundle(long bundleIdentifier) throws IOException { Bundle bundle = FrameworkUtils.resolveBundle(context, bundleIdentifier); try { bundle.update(); } catch (Exception be) { IOException ioex = new IOException("Update of bundle with id " + bundleIdentifier + " failed with message: " + be.getMessage()); ioex.initCause(be); throw ioex; } } /** * @see org.osgi.jmx.framework.FrameworkMBean#updateBundleFromURL(long, String) */ public void updateBundleFromURL(long bundleIdentifier, String url) throws IOException { Bundle bundle = FrameworkUtils.resolveBundle(context, bundleIdentifier); InputStream inputStream = null; try { inputStream = createStream(url); bundle.update(inputStream); } catch (Exception be) { IOException ioex = new IOException("Update of bundle with id " + bundleIdentifier + " from url " + url + " failed with message: " + be.getMessage()); ioex.initCause(be); throw ioex; } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException ioe) { } } } } /** * @see org.osgi.jmx.framework.FrameworkMBean#updateBundles(long[]) */ public CompositeData updateBundles(long[] bundleIdentifiers) throws IOException { if (bundleIdentifiers == null) { return new BatchActionResult("Failed to update bundles, bundle id's can't be null").toCompositeData(); } for (int i = 0; i < bundleIdentifiers.length; i++) { try { updateBundle(bundleIdentifiers[i]); } catch (Throwable t) { return createFailedBatchActionResult(bundleIdentifiers, i, t); } } return new BatchActionResult(bundleIdentifiers).toCompositeData(); } /** * @see org.osgi.jmx.framework.FrameworkMBean#updateBundlesFromURL(long[], String[]) */ public CompositeData updateBundlesFromURL(long[] bundleIdentifiers, String[] urls) throws IOException { if(bundleIdentifiers == null || urls == null){ return new BatchActionResult("Failed to update bundles arguments can't be null").toCompositeData(); } if(bundleIdentifiers != null && urls != null && bundleIdentifiers.length != urls.length){ return new BatchActionResult("Failed to update bundles size of arguments should be same").toCompositeData(); } for (int i = 0; i < bundleIdentifiers.length; i++) { try { updateBundleFromURL(bundleIdentifiers[i], urls[i]); } catch (Throwable t) { return createFailedBatchActionResult(bundleIdentifiers, i, t); } } return new BatchActionResult(bundleIdentifiers).toCompositeData(); } /** * @see org.osgi.jmx.framework.FrameworkMBean#updateFramework() */ public void updateFramework() throws IOException { Bundle bundle = FrameworkUtils.resolveBundle(context, 0); try { bundle.update(); } catch (Exception be) { IOException ioex = new IOException("Update of framework bundle failed with message: " + be.getMessage()); ioex.initCause(be); throw ioex; } } /** * Create {@link BatchActionResult}, when the operation fail. * * @param bundleIdentifiers bundle ids for operation. * @param i index of loop pointing on which operation fails. * @param t Throwable thrown by failed operation. * @return created BatchActionResult instance. */ private CompositeData createFailedBatchActionResult(long[] bundleIdentifiers, int i, Throwable t) { long[] completed = new long[i]; System.arraycopy(bundleIdentifiers, 0, completed, 0, i); long[] remaining = new long[bundleIdentifiers.length - i - 1]; System.arraycopy(bundleIdentifiers, i + 1, remaining, 0, remaining.length); return new BatchActionResult(completed, t.toString(), remaining, bundleIdentifiers[i]).toCompositeData(); } }