Package org.apache.felix.deploymentadmin

Source Code of org.apache.felix.deploymentadmin.AbstractDeploymentPackage$EmptyDeploymentPackage

/*
* 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.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.Manifest;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.Version;
import org.osgi.service.deploymentadmin.BundleInfo;
import org.osgi.service.deploymentadmin.DeploymentException;
import org.osgi.service.deploymentadmin.DeploymentPackage;
import org.osgi.service.deploymentadmin.spi.ResourceProcessor;
import org.osgi.service.log.LogService;

/**
* Base class for various types of deployment packages. Indifferent in regard to
* how the deployment package data is obtained, this should be handled by
* extending classes.
*/
public abstract class AbstractDeploymentPackage implements DeploymentPackage, Constants {
    /**
     * Represents an empty deployment package.
     */
    private static final class EmptyDeploymentPackage extends AbstractDeploymentPackage {
        private static final String[] STRINGS = new String[] {};
        private static final ResourceInfoImpl[] RESOURCE_INFO_IMPLS = new ResourceInfoImpl[] {};
        private static final BundleInfoImpl[] BUNDLE_INFO_IMPLS = new BundleInfoImpl[] {};

        public Bundle getBundle(String symbolicName) {
            return null;
        }

        public BundleInfoImpl[] getBundleInfoImpls() {
            return BUNDLE_INFO_IMPLS;
        }

        public BundleInfo[] getBundleInfos() {
            return BUNDLE_INFO_IMPLS;
        }

        public InputStream getBundleStream(String symbolicName) throws IOException {
            return null;
        }

        public InputStream getCurrentEntryStream() {
            throw new UnsupportedOperationException();
        }

        public String getDisplayName() {
            return "";
        }

        public String getHeader(String header) {
            if (DEPLOYMENTPACKAGE_SYMBOLICMAME.equals(header)) {
                return "";
            }
            else if (DEPLOYMENTPACKAGE_VERSION.equals(header)) {
                return Version.emptyVersion.toString();
            }
            else {
                return null;
            }
        }

        public URL getIcon() {
            return null;
        }

        public String getName() {
            return "";
        }

        public AbstractInfo getNextEntry() throws IOException {
            throw new UnsupportedOperationException();
        }

        public BundleInfoImpl[] getOrderedBundleInfos() {
            return BUNDLE_INFO_IMPLS;
        }

        public ResourceInfoImpl[] getOrderedResourceInfos() {
            return RESOURCE_INFO_IMPLS;
        }

        public String getResourceHeader(String resource, String header) {
            return null;
        }

        public ResourceInfoImpl[] getResourceInfos() {
            return RESOURCE_INFO_IMPLS;
        }

        public ServiceReference getResourceProcessor(String resource) {
            return null;
        }

        public String[] getResources() {
            return STRINGS;
        }

        public Version getVersion() {
            return Version.emptyVersion;
        }

        public boolean isStale() {
            return true;
        }

        public void uninstall() throws DeploymentException {
            throw new IllegalStateException("Can not uninstall stale DeploymentPackage");
        }

        public boolean uninstallForced() throws DeploymentException {
            throw new IllegalStateException("Can not uninstall stale DeploymentPackage");
        }
    }

    protected static final AbstractDeploymentPackage EMPTY_PACKAGE = new EmptyDeploymentPackage();

    private final BundleContext m_bundleContext;
    private final DeploymentAdminImpl m_deploymentAdmin;
    private final DeploymentPackageManifest m_manifest;
    private final Map m_nameToBundleInfo = new HashMap();
    private final Map m_pathToEntry = new HashMap();
    private final BundleInfoImpl[] m_bundleInfos;
    private final ResourceInfoImpl[] m_resourceInfos;
    private final String[] m_resourcePaths;
    private final boolean m_isFixPackage;
    private boolean m_isStale;

    /**
     * Creates an instance of this class.
     *
     * @param manifest The manifest of the deployment package.
     * @param bundleContext The bundle context.
     * @throws DeploymentException Thrown if the specified manifest does not
     *         describe a valid deployment package.
     */
    public AbstractDeploymentPackage(Manifest manifest, BundleContext bundleContext, DeploymentAdminImpl deploymentAdmin) throws DeploymentException {
        m_manifest = new DeploymentPackageManifest(manifest);
        m_isFixPackage = m_manifest.getFixPackage() != null;
        m_bundleContext = bundleContext;
        m_deploymentAdmin = deploymentAdmin;

        List bundleInfos = m_manifest.getBundleInfos();
        m_bundleInfos = (BundleInfoImpl[]) bundleInfos.toArray(new BundleInfoImpl[bundleInfos.size()]);

        for (int i = 0; i < m_bundleInfos.length; i++) {
            String bsn = m_bundleInfos[i].getSymbolicName();
            if (m_nameToBundleInfo.put(bsn, m_bundleInfos[i]) != null) {
                // FELIX-4463: make sure that the DP is consistent...
                throw new DeploymentException(CODE_OTHER_ERROR, "Duplicate bundle present in deployment package: " + bsn);
            }

            String path = m_bundleInfos[i].getPath();
            if (m_pathToEntry.put(path, m_bundleInfos[i]) != null) {
                // FELIX-4463: make sure that the DP is consistent...
                throw new DeploymentException(CODE_OTHER_ERROR, "Non-unique path present in deployment package: " + path);
            }
        }

        List resourceInfos = m_manifest.getResourceInfos();
        m_resourceInfos = (ResourceInfoImpl[]) resourceInfos.toArray(new ResourceInfoImpl[resourceInfos.size()]);

        for (int i = 0; i < m_resourceInfos.length; i++) {
            String path = m_resourceInfos[i].getPath();
            if (m_pathToEntry.put(path, m_resourceInfos[i]) != null) {
                // FELIX-4463: make sure that the DP is consistent...
                throw new DeploymentException(CODE_OTHER_ERROR, "Non-unique path present in deployment package: " + path);
            }
        }
        m_resourcePaths = (String[]) m_pathToEntry.keySet().toArray(new String[m_pathToEntry.size()]);
    }

    /* Constructor only for use by the emptyPackage static variable */
    private AbstractDeploymentPackage() {
        m_bundleContext = null;
        m_manifest = null;
        m_bundleInfos = null;
        m_resourceInfos = null;
        m_resourcePaths = null;
        m_isFixPackage = false;
        m_deploymentAdmin = null;
    }

    public Bundle getBundle(String symbolicName) {
        if (isStale()) {
            throw new IllegalStateException("Can not get bundle from stale deployment package.");
        }

        BundleInfo bundleInfo = (BundleInfo) m_nameToBundleInfo.get(symbolicName);
        if (bundleInfo != null) {
            Version version = bundleInfo.getVersion();

            Bundle[] bundles = m_bundleContext.getBundles();
            for (int i = 0; i < bundles.length; i++) {
                if (symbolicName.equals(bundles[i].getSymbolicName()) && version.equals(bundles[i].getVersion())) {
                    return bundles[i];
                }
            }
        }
        return null;
    }

    /**
     * Determines the info about a bundle resource based on the bundle symbolic
     * name.
     *
     * @param symbolicName String containing a bundle symbolic name
     * @return <code>BundleInfoImpl</code> for the bundle identified by the
     *         specified symbolic name or null if the symbolic name is unknown
     */
    public BundleInfoImpl getBundleInfoByName(String symbolicName) {
        return (BundleInfoImpl) m_nameToBundleInfo.get(symbolicName);
    }

    /**
     * Determines the info about a bundle based on it's path/resource-id.
     *
     * @param path String containing a bundle path
     * @return <code>BundleInfoImpl</code> for the bundle resource identified by
     *         the specified path or null if the path is unknown or does not
     *         describe a bundle resource
     */
    public BundleInfoImpl getBundleInfoByPath(String path) {
        AbstractInfo info = (AbstractInfo) m_pathToEntry.get(path);
        if (info instanceof BundleInfoImpl) {
            return (BundleInfoImpl) info;
        }
        return null;
    }

    /**
     * Returns the bundles of this deployment package as an array of
     * <code>BundleInfoImpl</code> objects.
     *
     * @return Array containing <code>BundleInfoImpl</code> objects for each
     *         bundle this deployment package.
     */
    public BundleInfoImpl[] getBundleInfoImpls() {
        return (BundleInfoImpl[]) m_bundleInfos.clone();
    }

    public BundleInfo[] getBundleInfos() {
        return (BundleInfo[]) m_bundleInfos.clone();
    }

    /**
     * Determines the data stream of a bundle resource based on the bundle
     * symbolic name
     *
     * @param symbolicName Bundle symbolic name
     * @return Stream to the bundle identified by the specified symbolic name or
     *         null if no such bundle exists in this deployment package.
     * @throws IOException If the bundle can not be properly offered as an
     *         inputstream
     */
    public abstract InputStream getBundleStream(String symbolicName) throws IOException;

    /**
     * Determines the data stream to the current entry of this deployment
     * package, use this together with the <code>getNextEntry</code> method.
     *
     * @return Stream to the current resource in the deployment package (as
     *         determined by the order in which the deployment package was
     *         received originally) or null if there is no entry
     */
    public abstract InputStream getCurrentEntryStream();

    public String getDisplayName() {
        return getHeader(DEPLOYMENTPACKAGE_NAME);
    }

    public String getHeader(String header) {
        return m_manifest.getHeader(header);
    }

    public URL getIcon() {
        String icon = getHeader(DEPLOYMENTPACKAGE_ICON);
        if (icon == null) {
            return null;
        }
        else {
            try {
                // TODO spec states this must be a local resource, but we don't make sure of that yet
                return new URL(icon);
            }
            catch (MalformedURLException e) {
                return null;
            }
        }
    }

    public String getName() {
        return m_manifest.getSymbolicName();
    }

    /**
     * Determines the next resource entry in this deployment package based on
     * the order in which the resources appeared when the package was originally
     * received.
     *
     * @return <code>AbstractInfo</code> describing the next resource entry (as
     *         determined by the order in which the deployment package was
     *         received originally) or null if there is no next entry
     * @throws IOException if the next entry can not be properly determined
     */
    public abstract AbstractInfo getNextEntry() throws IOException;

    /**
     * Determines the bundles of this deployment package in the order in which
     * they were originally received.
     *
     * @return Array containing <code>BundleInfoImpl</code> objects of the
     *         bundles in this deployment package, ordered in the way they
     *         appeared when the deployment package was first received.
     */
    public abstract BundleInfoImpl[] getOrderedBundleInfos();

    /**
     * Determines the resources of this deployment package in the order in which
     * they were originally received.
     *
     * @return Array containing <code>ResourceInfoImpl</code> objects of all
     *         processed resources in this deployment package, ordered in the
     *         way they appeared when the deployment package was first received
     */
    public abstract ResourceInfoImpl[] getOrderedResourceInfos();

    public String getResourceHeader(String resource, String header) {
        AbstractInfo info = (AbstractInfo) m_pathToEntry.get(resource);
        if (info != null) {
            return info.getHeader(header);
        }
        return null;
    }

    /**
     * Determines the info about a processed resource based on it's
     * path/resource-id.
     *
     * @param path String containing a (processed) resource path
     * @return <code>ResourceInfoImpl</code> for the resource identified by the
     *         specified path or null if the path is unknown or does not
     *         describe a processed resource
     */
    public ResourceInfoImpl getResourceInfoByPath(String path) {
        AbstractInfo info = (AbstractInfo) m_pathToEntry.get(path);
        if (info instanceof ResourceInfoImpl) {
            return (ResourceInfoImpl) info;
        }
        return null;
    }

    /**
     * Returns the processed resources of this deployment package as an array of
     * <code>ResourceInfoImpl</code> objects.
     *
     * @return Array containing <code>ResourceInfoImpl</code> objects for each
     *         processed resource of this deployment package.
     */
    public ResourceInfoImpl[] getResourceInfos() {
        return (ResourceInfoImpl[]) m_resourceInfos.clone();
    }

    public ServiceReference getResourceProcessor(String resource) {
        if (isStale()) {
            throw new IllegalStateException("Can not get bundle from stale deployment package.");
        }
        AbstractInfo info = (AbstractInfo) m_pathToEntry.get(resource);
        if (info instanceof ResourceInfoImpl) {
            String processor = ((ResourceInfoImpl) info).getResourceProcessor();
            if (processor != null) {
                try {
                    ServiceReference[] services = m_bundleContext.getServiceReferences(ResourceProcessor.class.getName(), "(" + SERVICE_PID + "=" + processor + ")");
                    if (services != null && services.length > 0) {
                        return services[0];
                    }
                    else {
                        return null;
                    }
                }
                catch (InvalidSyntaxException e) {
                    m_deploymentAdmin.getLog().log(LogService.LOG_WARNING, "Invalid resource processor name: " + processor, e);
                    return null;
                }
            }
        }
        return null;
    }

    public String[] getResources() {
        return (String[]) m_resourcePaths.clone();
    }

    public Version getVersion() {
        return m_manifest.getVersion();
    }

    /**
     * If this deployment package is a fix package this method determines the
     * version range this deployment package can be applied to.
     *
     * @return <code>VersionRange</code> the fix package can be applied to or
     *         <code>null</code> if it is not a fix package.
     */
    public VersionRange getVersionRange() {
        return m_manifest.getFixPackage();
    }

    /**
     * Determines whether this deployment package is a fix package.
     *
     * @return True if this deployment package is a fix package, false
     *         otherwise.
     */
    public boolean isFixPackage() {
        return m_isFixPackage;
    }

    /**
     * @return <code>true</code> if this package is actually an empty package
     *         used for installing new deployment packages, <code>false</code>
     *         otherwise.
     */
    public boolean isNew() {
        return this == EMPTY_PACKAGE;
    }

    public boolean isStale() {
        return m_isStale;
    }

    public void setStale(boolean isStale) {
        m_isStale = isStale;
    }

    public void uninstall() throws DeploymentException {
        if (isStale()) {
            throw new IllegalStateException("Deployment package is stale, cannot uninstall!");
        }

        m_deploymentAdmin.uninstallDeploymentPackage(this, false /* force */);
        // FELIX-4484: only mark a DP as stale when it is *successfully* uninstalled...
        setStale(true);
    }

    public boolean uninstallForced() throws DeploymentException {
        if (isStale()) {
            throw new IllegalStateException("Deployment package is stale, cannot force uninstallation!");
        }

        try {
            m_deploymentAdmin.uninstallDeploymentPackage(this, true /* force */);
        }
        finally {
            // FELIX-4484: this is a best-effort method, if it fails, we cannot do anything about it anymore...
            setStale(true);
        }
        return true;
    }

    /**
     * Determines the info about either a bundle or processed resource based on
     * it's path/resource-id.
     *
     * @param path String containing a resource path (either bundle or processed
     *        resource)
     * @return <code>AbstractInfoImpl</code> for the resource identified by the
     *         specified path or null if the path is unknown
     */
    protected AbstractInfo getAbstractInfoByPath(String path) {
        return (AbstractInfo) m_pathToEntry.get(path);
    }

}
TOP

Related Classes of org.apache.felix.deploymentadmin.AbstractDeploymentPackage$EmptyDeploymentPackage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.