All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.web.osgi.OSGiBundleArchive Maven / Gradle / Ivy

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */


package org.glassfish.web.osgi;

import org.glassfish.api.deployment.archive.Archive;
import org.glassfish.api.deployment.archive.ReadableArchive;
import static org.glassfish.web.osgi.Constants.FILE_PROTOCOL;
import static org.glassfish.web.osgi.Constants.REFERENCE_PROTOCOL;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;
import static org.osgi.framework.Constants.BUNDLE_VERSION;

import java.io.IOException;
import java.io.InputStream;
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.ListIterator;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import com.sun.enterprise.deployment.deploy.shared.Util;

/**
 * Adapts a {@link Bundle} to {@link Archive}.
 * It uses JAR File space of the bundle (via getEntry and getEntryPaths APIs),
 * so a bundle does not have to be in resolved state.
 * Since it represents JAR File space of the bundle, it does not
 * consider resources from any fragments.
 *
 * @author [email protected]
 */
public class OSGiBundleArchive implements ReadableArchive
{
    private Bundle b;

    private String name;

    private URI uri;

    public OSGiBundleArchive(Bundle b)
    {
        this.b = b;
        init();
    }

    /**
     * This method initializes {@link #uri} and {@link #name}
     */
    private void init() {
        // The only time we can rely on a bundle's location is when the
        // location string begins with reference: scheme, as both Felix and
        // equinox assumes that the rest of the location is a file.
        // In no other case, we can use rely on bundle.getLocation()
        // to arrive at the URI of the underlying archive.
        // e.g., user can install like this:
        // bundleContext.install ("file:/a/b.jar", new URL("file:/c/d.jar").openStream));
        // In the above case, although location returns a.jar, the actual archive
        // is read from d.jar.
        // So, we return a valid URI only for reference: scheme and in all
        // cases, we prefer to return null as opposed to throwing an exception
        // to keep the behavior same as MemoryMappedArchive.
        String location = b.getLocation();
        if (location != null && location.startsWith(REFERENCE_PROTOCOL))
        {
            location = location.substring(REFERENCE_PROTOCOL.length());

            // We only know how to handle reference:file: type urls.
            if (location.startsWith(FILE_PROTOCOL))
            {

                // Decode any URL escaped sequences.
                location = URLDecoder.decode(location);

                // Return iff referenced file exists.
                File file = new File(location.substring(FILE_PROTOCOL.length()));
                if (file.exists())
                {
                    uri = file.toURI();
                }
            }
        }

        // See issue #10536. We can't use the same policy for obtaining
        // the name as OSGi container does.
//        if (uri != null) {
//            name = Util.getURIName(uri);
//        } else {
            // See if there is a symbolic name & version. Use them,
            // else use location. Either symbolic name or location must exist
            // in a bundle.
            String symName = b.getSymbolicName();
            String version = (String)b.getHeaders().get(BUNDLE_VERSION);
            if (symName != null) {
                name = version== null ?
                        symName : symName.concat("_").concat(version);
            } else {
                name = location;
            }
//        }
    }

    public void close() throws IOException
    {
    }

    public Enumeration entries()
    {
        return Collections.enumeration(entries(false)); // return only file entries as per contract of this method
    }

    public Collection getDirectories() throws IOException
    {
        return entries(true);
    }

    private Collection entries(boolean directories)
    {
        ArrayList entries = new ArrayList();
        getEntryPaths(entries, "/");
        ListIterator entriesIter = entries.listIterator();
        while (entriesIter.hasNext())
        {
            String next = entriesIter.next();
            if (next.endsWith("/"))
            {
                // return only file entries as per the conract of this method
                entriesIter.remove();
            }
        }
        return entries;
    }

    private void getEntryPaths(Collection entries, String path)
    {
//        BECAUSE OF A BUG IN FELIX, THE CODE BELOW DOES NOT WORK
//        WHEN THERE ARE NO DIRECTORY ENTRIES IN THE JAR FILE.
//        SO, WE ARE USING findEntries WHICH HAS AN UNDESIRED SIDE EFFECT
//        OF RETURNING ENTRIES FROM FRAGMENTS. SO, AS SOON AS THE BUG
//        IS FIXED IN FELIX, WE SHOULD SWITCH TO THE FOLLOWING CODE.
//        Enumeration subPaths = b.getEntryPaths(path);
//        if (subPaths != null)
//        {
//            while (subPaths.hasMoreElements())
//            {
//                String next = subPaths.nextElement();
//                entries.add(next);
//                getEntryPaths(entries, next);
//            }
//        }
        getEntryPaths2(entries, path); // call the new implementation
    }

    private void getEntryPaths2(Collection entries, String path) {
        // findEntries expect the path to begin with "/"
        Enumeration e = b.findEntries(
                path.startsWith("/") ? path : path.concat("/"), "*", true);
         if (e != null) {
             while (e.hasMoreElements()) {
                 URL next = (URL)e.nextElement();
                 String nextPath = next.getPath();
                 // As per the OSGi R4 spec,
                 // "The getPath method for a bundle entry URL must return
                 // an absolute path (a path that starts with '/') to a resource
                 // or entry in a bundle. For example, the URL returned from
                 // getEntry("myimages/test .gif ") must have a path of
                 // /myimages/test.gif.
                 entries.add(nextPath.substring(1)); // remove the leading "/"
             }
         }
    }

    public Enumeration entries(String prefix)
    {
        Collection entries = new ArrayList();
        getEntryPaths(entries, prefix);
        return Collections.enumeration(entries);
    }

    public boolean isDirectory(String name)
    {
        return b.getEntryPaths(name) != null;
    }

    public Manifest getManifest() throws IOException
    {
        URL url = b.getEntry(JarFile.MANIFEST_NAME);
        if (url != null)
        {
            InputStream is = url.openStream();
            try
            {
                return new Manifest(is);
            }
            finally
            {
                is.close();
            }

        }
        return null;
    }

    /**
     * It returns URI for the underlying file if it can locate such a file.
     * Else, it returns null.
     * @return
     */
    public URI getURI()
    {
        return uri;
    }

    public long getArchiveSize() throws SecurityException
    {
        return -1; // Don't know how to calculate the size.
    }

    public String getName()
    {
        return name;
    }

    public InputStream getEntry(String name) throws IOException
    {
        URL entry = b.getEntry(name);
        return entry != null ? entry.openStream() : null;
    }

    public boolean exists(String name) throws IOException
    {
        return b.getEntry(name)!=null;
    }

    public long getEntrySize(String name)
    {
        return 0;
    }

    public void open(URI uri) throws IOException
    {
        throw new UnsupportedOperationException("Not supported");
    }

    public ReadableArchive getSubArchive(String name) throws IOException
    {
        return null;
    }

    public boolean exists()
    {
        return true;
    }

    public boolean delete()
    {
        return false;
    }

    public boolean renameTo(String name)
    {
        return false;
    }

    public void setParentArchive(ReadableArchive parentArchive)
    {
        // Not needed until we support ear file containing bundles.
        throw new UnsupportedOperationException("Not supported");
    }

    public ReadableArchive getParentArchive()
    {
        return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy