| /* |
| * 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.felix.deploymentadmin; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Dictionary; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.jar.JarInputStream; |
| |
| import org.apache.felix.deploymentadmin.spi.CommitResourceCommand; |
| import org.apache.felix.deploymentadmin.spi.DeploymentSessionImpl; |
| import org.apache.felix.deploymentadmin.spi.DropAllBundlesCommand; |
| import org.apache.felix.deploymentadmin.spi.DropAllResourcesCommand; |
| import org.apache.felix.deploymentadmin.spi.DropBundleCommand; |
| import org.apache.felix.deploymentadmin.spi.DropResourceCommand; |
| import org.apache.felix.deploymentadmin.spi.GetStorageAreaCommand; |
| import org.apache.felix.deploymentadmin.spi.ProcessResourceCommand; |
| import org.apache.felix.deploymentadmin.spi.SnapshotCommand; |
| import org.apache.felix.deploymentadmin.spi.StartBundleCommand; |
| import org.apache.felix.deploymentadmin.spi.StartCustomizerCommand; |
| import org.apache.felix.deploymentadmin.spi.StopBundleCommand; |
| import org.apache.felix.deploymentadmin.spi.UpdateCommand; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.Version; |
| import org.osgi.service.deploymentadmin.DeploymentAdmin; |
| import org.osgi.service.deploymentadmin.DeploymentException; |
| import org.osgi.service.deploymentadmin.DeploymentPackage; |
| import org.osgi.service.event.Event; |
| import org.osgi.service.event.EventAdmin; |
| import org.osgi.service.log.LogService; |
| import org.osgi.service.packageadmin.PackageAdmin; |
| |
| public class DeploymentAdminImpl implements DeploymentAdmin, Constants { |
| public static final String PACKAGE_DIR = "packages"; |
| public static final String TEMP_DIR = "temp"; |
| public static final String PACKAGECONTENTS_DIR = "contents"; |
| public static final String PACKAGEINDEX_FILE = "index.txt"; |
| public static final String TEMP_PREFIX = "pkg"; |
| public static final String TEMP_POSTFIX = ""; |
| |
| private static final long TIMEOUT = 10000; |
| |
| private volatile BundleContext m_context; /* will be injected by dependencymanager */ |
| private volatile PackageAdmin m_packageAdmin; /* will be injected by dependencymanager */ |
| private volatile EventAdmin m_eventAdmin; /* will be injected by dependencymanager */ |
| private volatile LogService m_log; /* will be injected by dependencymanager */ |
| private volatile DeploymentSessionImpl m_session; |
| |
| private final Map /* BSN -> DeploymentPackage */m_packages = new HashMap(); |
| private final Semaphore m_semaphore = new Semaphore(); |
| |
| /** |
| * Creates a new {@link DeploymentAdminImpl} instance. |
| */ |
| public DeploymentAdminImpl() { |
| // Nop |
| } |
| |
| /** |
| * Creates a new {@link DeploymentAdminImpl} instance. |
| */ |
| DeploymentAdminImpl(BundleContext context) { |
| m_context = context; |
| } |
| |
| public boolean cancel() { |
| DeploymentSessionImpl session = m_session; |
| if (session != null) { |
| session.cancel(); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Returns reference to this bundle's <code>BundleContext</code> |
| * |
| * @return This bundle's <code>BundleContext</code> |
| */ |
| public BundleContext getBundleContext() { |
| return m_context; |
| } |
| |
| public DeploymentPackage getDeploymentPackage(Bundle bundle) { |
| if (bundle == null) { |
| throw new IllegalArgumentException("Bundle can not be null"); |
| } |
| return getDeploymentPackageContainingBundleWithSymbolicName(bundle.getSymbolicName()); |
| } |
| |
| public DeploymentPackage getDeploymentPackage(String symbName) { |
| if (symbName == null) { |
| throw new IllegalArgumentException("Symbolic name may not be null"); |
| } |
| return (DeploymentPackage) m_packages.get(symbName); |
| } |
| |
| /** |
| * Returns reference to the current logging service defined in the framework. |
| * |
| * @return Currently active <code>LogService</code>. |
| */ |
| public LogService getLog() { |
| return m_log; |
| } |
| |
| /** |
| * Returns reference to the current package admin defined in the framework. |
| * |
| * @return Currently active <code>PackageAdmin</code>. |
| */ |
| public PackageAdmin getPackageAdmin() { |
| return m_packageAdmin; |
| } |
| |
| public DeploymentPackage installDeploymentPackage(InputStream sourceInput) throws DeploymentException { |
| if (sourceInput == null) { |
| throw new IllegalArgumentException("Inputstream may not be null"); |
| } |
| |
| try { |
| if (!m_semaphore.tryAcquire(TIMEOUT)) { |
| throw new DeploymentException(CODE_TIMEOUT, "Timeout exceeded while waiting to install deployment package (" + TIMEOUT + " ms)"); |
| } |
| } |
| catch (InterruptedException ie) { |
| throw new DeploymentException(CODE_TIMEOUT, "Thread interrupted"); |
| } |
| |
| File tempPackage = null; |
| StreamDeploymentPackage source = null; |
| AbstractDeploymentPackage target = null; |
| boolean succeeded = false; |
| |
| try { |
| JarInputStream jarInput = null; |
| File tempIndex = null; |
| File tempContents = null; |
| try { |
| File tempDir = m_context.getDataFile(TEMP_DIR); |
| tempDir.mkdirs(); |
| tempPackage = File.createTempFile(TEMP_PREFIX, TEMP_POSTFIX, tempDir); |
| tempPackage.delete(); |
| tempPackage.mkdirs(); |
| tempIndex = new File(tempPackage, PACKAGEINDEX_FILE); |
| tempContents = new File(tempPackage, PACKAGECONTENTS_DIR); |
| tempContents.mkdirs(); |
| } |
| catch (IOException e) { |
| m_log.log(LogService.LOG_ERROR, "Error writing package to disk", e); |
| throw new DeploymentException(CODE_OTHER_ERROR, "Error writing package to disk", e); |
| } |
| |
| try { |
| jarInput = new ContentCopyingJarInputStream(sourceInput, tempIndex, tempContents); |
| |
| if (jarInput.getManifest() == null) { |
| Utils.closeSilently(jarInput); |
| |
| m_log.log(LogService.LOG_ERROR, "Stream does not contain a valid deployment package: missing manifest!"); |
| throw new DeploymentException(CODE_MISSING_HEADER, "No manifest present in deployment package!"); |
| } |
| } |
| catch (IOException e) { |
| m_log.log(LogService.LOG_ERROR, "Stream does not contain a valid Jar", e); |
| throw new DeploymentException(CODE_NOT_A_JAR, "Stream does not contain a valid Jar", e); |
| } |
| |
| source = new StreamDeploymentPackage(jarInput, m_context, this); |
| String dpSymbolicName = source.getName(); |
| |
| target = getExistingOrEmptyDeploymentPackage(dpSymbolicName); |
| |
| // Fire an event that we're about to install a new package |
| sendStartedEvent(source, target); |
| |
| // Assert that: |
| // the source has no bundles that exists in other packages than the target. |
| verifyNoResourcesShared(source, target); |
| |
| if (source.isFixPackage()) { |
| // Assert that: |
| // a. the version of the target matches the required fix-package range; |
| // b. all missing source bundles are present in the target. |
| verifyFixPackage(source, target); |
| } |
| else { |
| // Assert that: |
| // no missing resources or bundles are declared. |
| verifySourcePackage(source); |
| } |
| |
| try { |
| m_session = new DeploymentSessionImpl(source, target, createInstallCommandChain(), this, new DeploymentAdminConfig(m_context)); |
| m_session.call(false /* ignoreExceptions */); |
| } |
| catch (DeploymentException de) { |
| throw de; |
| } |
| finally { |
| // We're done at this point with the JAR input stream, close it here as to avoid keeping |
| // files open unnecessary (otherwise it fails on Windows)... |
| Utils.closeSilently(jarInput); |
| } |
| |
| String dpInstallBaseDirectory = PACKAGE_DIR + File.separator + dpSymbolicName; |
| |
| File targetContents = m_context.getDataFile(dpInstallBaseDirectory + File.separator + PACKAGECONTENTS_DIR); |
| File targetIndex = m_context.getDataFile(dpInstallBaseDirectory + File.separator + PACKAGEINDEX_FILE); |
| |
| if (source.isFixPackage()) { |
| try { |
| Utils.merge(targetIndex, targetContents, tempIndex, tempContents); |
| } |
| catch (IOException e) { |
| m_log.log(LogService.LOG_ERROR, "Could not merge source fix package with target deployment package", e); |
| throw new DeploymentException(CODE_OTHER_ERROR, "Could not merge source fix package with target deployment package", e); |
| } |
| } |
| else { |
| File targetPackage = m_context.getDataFile(dpInstallBaseDirectory); |
| targetPackage.mkdirs(); |
| if (!Utils.replace(targetPackage, tempPackage)) { |
| throw new DeploymentException(CODE_OTHER_ERROR, "Could not replace " + targetPackage + " with " + tempPackage); |
| } |
| } |
| |
| FileDeploymentPackage fileDeploymentPackage = null; |
| try { |
| fileDeploymentPackage = new FileDeploymentPackage(targetIndex, targetContents, m_context, this); |
| m_packages.put(dpSymbolicName, fileDeploymentPackage); |
| } |
| catch (IOException e) { |
| m_log.log(LogService.LOG_ERROR, "Could not create installed deployment package from disk", e); |
| throw new DeploymentException(CODE_OTHER_ERROR, "Could not create installed deployment package from disk", e); |
| } |
| |
| // Since we're here, it means everything went OK, so we might as well raise our success flag... |
| succeeded = true; |
| |
| return fileDeploymentPackage; |
| } |
| finally { |
| if (tempPackage != null) { |
| if (!Utils.delete(tempPackage, true)) { |
| m_log.log(LogService.LOG_ERROR, "Could not delete temporary deployment package from disk"); |
| succeeded = false; |
| } |
| } |
| |
| sendCompleteEvent(source, target, succeeded); |
| m_semaphore.release(); |
| } |
| } |
| |
| public DeploymentPackage[] listDeploymentPackages() { |
| Collection packages = m_packages.values(); |
| return (DeploymentPackage[]) packages.toArray(new DeploymentPackage[packages.size()]); |
| } |
| |
| /** |
| * Called by dependency manager upon start of this component. |
| */ |
| public void start() throws DeploymentException { |
| File packageDir = m_context.getDataFile(PACKAGE_DIR); |
| if (packageDir == null) { |
| throw new DeploymentException(CODE_OTHER_ERROR, "Could not create directories needed for deployment package persistence"); |
| } |
| else if (packageDir.isDirectory()) { |
| File[] dpPackages = packageDir.listFiles(); |
| for (int i = 0; i < dpPackages.length; i++) { |
| File dpPackageDir = dpPackages[i]; |
| if (!dpPackageDir.isDirectory()) { |
| continue; |
| } |
| |
| try { |
| File index = new File(dpPackageDir, PACKAGEINDEX_FILE); |
| File contents = new File(dpPackageDir, PACKAGECONTENTS_DIR); |
| FileDeploymentPackage dp = new FileDeploymentPackage(index, contents, m_context, this); |
| m_packages.put(dp.getName(), dp); |
| } |
| catch (IOException e) { |
| m_log.log(LogService.LOG_WARNING, "Could not read deployment package from disk, skipping: '" + dpPackageDir.getAbsolutePath() + "'"); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Called by dependency manager when stopping this component. |
| */ |
| public void stop() { |
| cancel(); |
| } |
| |
| /** |
| * Uninstalls the given deployment package from the system. |
| * |
| * @param dp the deployment package to uninstall, cannot be <code>null</code>; |
| * @param forced <code>true</code> to force the uninstall, meaning that any exceptions are ignored during the |
| * uninstallation. |
| * @throws DeploymentException in case the uninstall failed. |
| */ |
| public void uninstallDeploymentPackage(DeploymentPackage dp, boolean forced) throws DeploymentException { |
| try { |
| if (!m_semaphore.tryAcquire(TIMEOUT)) { |
| throw new DeploymentException(CODE_TIMEOUT, "Timeout exceeded while waiting to uninstall deployment package (" + TIMEOUT + " ms)"); |
| } |
| } |
| catch (InterruptedException ie) { |
| throw new DeploymentException(CODE_TIMEOUT, "Thread interrupted"); |
| } |
| |
| boolean succeeded = false; |
| AbstractDeploymentPackage source = AbstractDeploymentPackage.EMPTY_PACKAGE; |
| AbstractDeploymentPackage target = (AbstractDeploymentPackage) dp; |
| |
| // Notify listeners that we've about to uninstall the deployment package... |
| sendUninstallEvent(source, target); |
| |
| try { |
| try { |
| m_session = new DeploymentSessionImpl(source, target, createUninstallCommandChain(), this, new DeploymentAdminConfig(m_context)); |
| m_session.call(forced /* ignoreExceptions */); |
| } |
| catch (DeploymentException de) { |
| throw de; |
| } |
| |
| File targetPackage = m_context.getDataFile(PACKAGE_DIR + File.separator + source.getName()); |
| if (!Utils.delete(targetPackage, true)) { |
| m_log.log(LogService.LOG_ERROR, "Could not delete deployment package from disk"); |
| throw new DeploymentException(CODE_OTHER_ERROR, "Could not delete deployment package from disk"); |
| } |
| |
| m_packages.remove(dp.getName()); |
| |
| succeeded = true; |
| } |
| finally { |
| sendCompleteEvent(source, target, succeeded); |
| m_semaphore.release(); |
| } |
| } |
| |
| /** |
| * Creates the properties for a new event. |
| * |
| * @param source the source package being installed; |
| * @param target the current installed package (can be new). |
| * @return the event properties, never <code>null</code>. |
| */ |
| private Dictionary createEventProperties(AbstractDeploymentPackage source, AbstractDeploymentPackage target) { |
| Dictionary props = new Properties(); |
| if (source != null) { |
| String displayName = source.getDisplayName(); |
| if (displayName == null) { |
| displayName = source.getName(); |
| } |
| |
| props.put(EVENTPROPERTY_DEPLOYMENTPACKAGE_NAME, source.getName()); |
| props.put(EVENTPROPERTY_DEPLOYMENTPACKAGE_READABLENAME, displayName); |
| if (!source.isNew()) { |
| props.put(EVENTPROPERTY_DEPLOYMENTPACKAGE_NEXTVERSION, source.getVersion()); |
| } |
| } |
| if ((target != null) && !target.isNew()) { |
| props.put(EVENTPROPERTY_DEPLOYMENTPACKAGE_CURRENTVERSION, target.getVersion()); |
| } |
| return props; |
| } |
| |
| private List createInstallCommandChain() { |
| List commandChain = new ArrayList(); |
| |
| GetStorageAreaCommand getStorageAreaCommand = new GetStorageAreaCommand(); |
| commandChain.add(getStorageAreaCommand); |
| commandChain.add(new StopBundleCommand()); |
| commandChain.add(new SnapshotCommand(getStorageAreaCommand)); |
| commandChain.add(new UpdateCommand()); |
| commandChain.add(new StartCustomizerCommand()); |
| CommitResourceCommand commitCommand = new CommitResourceCommand(); |
| commandChain.add(new ProcessResourceCommand(commitCommand)); |
| commandChain.add(new DropResourceCommand(commitCommand)); |
| commandChain.add(new DropBundleCommand()); |
| commandChain.add(commitCommand); |
| commandChain.add(new StartBundleCommand()); |
| |
| return commandChain; |
| } |
| |
| private List createUninstallCommandChain() { |
| List commandChain = new ArrayList(); |
| |
| GetStorageAreaCommand getStorageAreaCommand = new GetStorageAreaCommand(); |
| commandChain.add(getStorageAreaCommand); |
| commandChain.add(new StopBundleCommand()); |
| commandChain.add(new SnapshotCommand(getStorageAreaCommand)); |
| commandChain.add(new StartCustomizerCommand()); |
| CommitResourceCommand commitCommand = new CommitResourceCommand(); |
| commandChain.add(new DropAllResourcesCommand(commitCommand)); |
| commandChain.add(commitCommand); |
| commandChain.add(new DropAllBundlesCommand()); |
| |
| return commandChain; |
| } |
| |
| /** |
| * Searches for a deployment package that contains a bundle with the given symbolic name. |
| * |
| * @param symbolicName the symbolic name of the <em>bundle</em> to return the containing deployment package for, |
| * cannot be <code>null</code>. |
| * @return the deployment package containing the given bundle, or <code>null</code> if no deployment package |
| * contained such bundle. |
| */ |
| private AbstractDeploymentPackage getDeploymentPackageContainingBundleWithSymbolicName(String symbolicName) { |
| for (Iterator i = m_packages.values().iterator(); i.hasNext();) { |
| AbstractDeploymentPackage dp = (AbstractDeploymentPackage) i.next(); |
| if (dp.getBundle(symbolicName) != null) { |
| return dp; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns either an existing deployment package, or if no such package exists, an empty package. |
| * |
| * @param symbolicName the name of the deployment package to retrieve, cannot be <code>null</code>. |
| * @return a deployment package, never <code>null</code>. |
| */ |
| private AbstractDeploymentPackage getExistingOrEmptyDeploymentPackage(String symbolicName) { |
| AbstractDeploymentPackage result = (AbstractDeploymentPackage) m_packages.get(symbolicName); |
| if (result == null) { |
| result = AbstractDeploymentPackage.EMPTY_PACKAGE; |
| } |
| return result; |
| } |
| |
| /** |
| * Returns all bundles that are not present in any deployment package. Ultimately, this should only |
| * be one bundle, the system bundle, but this is not enforced in any way by the specification. |
| * |
| * @return an array of non-deployment packaged bundles, never <code>null</code>. |
| */ |
| private Bundle[] getNonDeploymentPackagedBundles() { |
| List result = new ArrayList(Arrays.asList(m_context.getBundles())); |
| |
| Iterator iter = result.iterator(); |
| while (iter.hasNext()) { |
| Bundle suspect = (Bundle) iter.next(); |
| if (suspect.getLocation().startsWith(BUNDLE_LOCATION_PREFIX)) { |
| iter.remove(); |
| } |
| } |
| |
| return (Bundle[]) result.toArray(new Bundle[result.size()]); |
| } |
| |
| /** |
| * Sends out an event that the {@link #installDeploymentPackage(InputStream)} is |
| * completed its installation of a deployment package. |
| * |
| * @param source the source package being installed; |
| * @param target the current installed package (can be new); |
| * @param success <code>true</code> if the installation was successful, <code>false</code> otherwise. |
| */ |
| private void sendCompleteEvent(AbstractDeploymentPackage source, AbstractDeploymentPackage target, boolean success) { |
| Dictionary props = createEventProperties(source, target); |
| props.put(EVENTPROPERTY_SUCCESSFUL, Boolean.valueOf(success)); |
| |
| m_eventAdmin.postEvent(new Event(EVENTTOPIC_COMPLETE, props)); |
| } |
| |
| /** |
| * Sends out an event that the {@link #installDeploymentPackage(InputStream)} is about |
| * to install a new deployment package. |
| * |
| * @param source the source package being installed; |
| * @param target the current installed package (can be new). |
| */ |
| private void sendStartedEvent(AbstractDeploymentPackage source, AbstractDeploymentPackage target) { |
| Dictionary props = createEventProperties(source, target); |
| |
| m_eventAdmin.postEvent(new Event(EVENTTOPIC_INSTALL, props)); |
| } |
| |
| /** |
| * Sends out an event that the {@link #uninstallDeploymentPackage(DeploymentPackage)} is about |
| * to uninstall a deployment package. |
| * |
| * @param source the source package being uninstalled; |
| * @param target the current installed package (can be new). |
| */ |
| private void sendUninstallEvent(AbstractDeploymentPackage source, AbstractDeploymentPackage target) { |
| Dictionary props = createEventProperties(source, target); |
| |
| m_eventAdmin.postEvent(new Event(EVENTTOPIC_UNINSTALL, props)); |
| } |
| |
| /** |
| * Verifies that the version of the target matches the required source version range, and |
| * whether all missing source resources are available in the target. |
| * |
| * @param source the fix-package source to verify; |
| * @param target the target package to verify against. |
| * @throws DeploymentException in case verification failed. |
| */ |
| private void verifyFixPackage(AbstractDeploymentPackage source, AbstractDeploymentPackage target) throws DeploymentException { |
| boolean newPackage = target.isNew(); |
| |
| // Verify whether the target package exists, and if so, falls in the requested fix-package range... |
| if (newPackage || (!source.getVersionRange().isInRange(target.getVersion()))) { |
| m_log.log(LogService.LOG_ERROR, "Target package version '" + target.getVersion() + "' is not in source range '" + source.getVersionRange() + "'"); |
| throw new DeploymentException(CODE_MISSING_FIXPACK_TARGET, "Target package version '" + target.getVersion() + "' is not in source range '" + source.getVersionRange() + "'"); |
| } |
| |
| // Verify whether all missing bundles are available in the target package... |
| BundleInfoImpl[] bundleInfos = source.getBundleInfoImpls(); |
| for (int i = 0; i < bundleInfos.length; i++) { |
| if (bundleInfos[i].isMissing()) { |
| // Check whether the bundle exists in the target package... |
| BundleInfoImpl targetBundleInfo = target.getBundleInfoByPath(bundleInfos[i].getPath()); |
| if (targetBundleInfo == null) { |
| m_log.log(LogService.LOG_ERROR, "Missing bundle '" + bundleInfos[i].getSymbolicName() + "/" + bundleInfos[i].getVersion() + " does not exist in target package!"); |
| throw new DeploymentException(CODE_MISSING_BUNDLE, "Missing bundle '" + bundleInfos[i].getSymbolicName() + "/" + bundleInfos[i].getVersion() + " does not exist in target package!"); |
| } |
| } |
| } |
| |
| // Verify whether all missing resources are available in the target package... |
| ResourceInfoImpl[] resourceInfos = source.getResourceInfos(); |
| for (int i = 0; i < resourceInfos.length; i++) { |
| if (resourceInfos[i].isMissing()) { |
| // Check whether the resource exists in the target package... |
| ResourceInfoImpl targetResourceInfo = target.getResourceInfoByPath(resourceInfos[i].getPath()); |
| if (targetResourceInfo == null) { |
| m_log.log(LogService.LOG_ERROR, "Missing resource '" + resourceInfos[i].getPath() + " does not exist in target package!"); |
| throw new DeploymentException(CODE_MISSING_RESOURCE, "Missing resource '" + resourceInfos[i].getPath() + " does not exist in target package!"); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Verifies whether none of the mentioned resources in the source package are present in |
| * deployment packages other than the given target. |
| * |
| * @param source the source package to verify; |
| * @param target the target package to verify against. |
| * @throws DeploymentException in case verification fails. |
| */ |
| private void verifyNoResourcesShared(AbstractDeploymentPackage source, AbstractDeploymentPackage target) throws DeploymentException { |
| Bundle[] foreignBundles = getNonDeploymentPackagedBundles(); |
| |
| // Verify whether all source bundles are available in the target package or absent... |
| BundleInfoImpl[] bundleInfos = source.getBundleInfoImpls(); |
| for (int i = 0; i < bundleInfos.length; i++) { |
| String symbolicName = bundleInfos[i].getSymbolicName(); |
| Version version = bundleInfos[i].getVersion(); |
| |
| DeploymentPackage targetPackage = getDeploymentPackageContainingBundleWithSymbolicName(symbolicName); |
| // If found, it should match the given target DP; not found is also ok... |
| if ((targetPackage != null) && !targetPackage.equals(target)) { |
| m_log.log(LogService.LOG_ERROR, "Bundle '" + symbolicName + "/" + version + " already present in other deployment packages!"); |
| throw new DeploymentException(CODE_BUNDLE_SHARING_VIOLATION, "Bundle '" + symbolicName + "/" + version + " already present in other deployment packages!"); |
| } |
| |
| if (targetPackage == null) { |
| // Maybe the bundle is installed without deployment admin... |
| for (int j = 0; j < foreignBundles.length; j++) { |
| if (symbolicName.equals(foreignBundles[j].getSymbolicName()) && version.equals(foreignBundles[j].getVersion())) { |
| m_log.log(LogService.LOG_ERROR, "Bundle '" + symbolicName + "/" + version + " already present!"); |
| throw new DeploymentException(CODE_BUNDLE_SHARING_VIOLATION, "Bundle '" + symbolicName + "/" + version + " already present!"); |
| } |
| } |
| } |
| } |
| |
| // TODO verify other resources as well... |
| } |
| |
| private void verifySourcePackage(AbstractDeploymentPackage source) throws DeploymentException { |
| // TODO this method should do a X-ref check between DP-manifest and JAR-entries... |
| // m_log.log(LogService.LOG_ERROR, "Missing bundle '" + symbolicName + "/" + bundleInfos[i].getVersion() + |
| // " does not exist in target package!"); |
| // throw new DeploymentException(CODE_OTHER_ERROR, "Missing bundle '" + symbolicName + "/" + bundleInfos[i].getVersion() |
| // + " is not part of target package!"); |
| } |
| } |