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

org.glassfish.internal.embedded.ScatteredArchive Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. 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_1_1.html
 * or packager/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 packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [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.internal.embedded;

import org.glassfish.api.deployment.archive.ReadableArchiveAdapter;

import java.io.*;
import java.net.URL;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.MalformedURLException;
import java.util.*;
import java.util.jar.Manifest;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import java.util.jar.JarEntry;

/**
 * Abstraction for a scattered archive (parts disseminated in various directories)
 *
 * @author Jerome Dochez
 */
public class ScatteredArchive extends ReadableArchiveAdapter {


    public static class Builder {

        final String name;
        File topDir = null;
        File resources = null;
        final List urls = new ArrayList();
        final Map metadata = new HashMap();


        /**
         * Construct a new scattered archive builder with the minimum information
         * By default, a scattered archive is not different from any other
         * archive where all the files are located under a top level
         * directory (topDir).
         * Some files can then be scattered in different locations and be specified
         * through the appropriate setters.
         * Alternatively, topDir can be null to specify a truely scattered archive
         * and all the locations must be specified.
         *
         * @param name   archive name
         * @param topDir top level directory
         */
        public Builder(String name, File topDir) {
            this.name = name;
            this.topDir = topDir;
        }

        /**
         * Construct a new scattered archive builder with a set of URLs as repository
         * for locating archive resources (like .class files).
         * @param name archive name
         * @param urls set of resources repository
         */
        public Builder(String name, Collection urls) {
            this.name = name;
            for (URL u : urls) {
                this.urls.add(u);
            }
        }

        /**
         * Sets the location of resources files
         *
         * @param resources the resources directory
         * @return itself
         */
        public Builder resources(File resources) {
            if (!resources.exists()) {
                throw new IllegalArgumentException(resources.getAbsolutePath() + " not found");
            }
            this.resources = resources;
            return this;
        }

        /**
         * Add a new metadata locator for this scattered archive. A metadata is identified
         * by its name (like WEB-INF/web.xml) and the location of the metadata is used when
         * the embedded server is requesting the metadata file.
         * The name for this metadata will be obtained by doing metadata.getName()
         *
         * @param metadata the metadata file location
         *
         * @return itself
         */
        public Builder addMetadata(File metadata) {
            if (!metadata.exists()) {
                throw new IllegalArgumentException(metadata.getAbsolutePath() + " not found");
            }
            return addMetadata(metadata.getName(), metadata);
        }

        /**
         * Add a new metadata locator for this scattered archive. A metadata is identified
         * by its name (like WEB-INF/web.xml) and the location of the metadata is used when
         * the embedded server is requesting the metadata file.
         *
         * @param name name of the metadata (eg WEB-INF/web.xml or web.xml or META-INF/ejb.xml
         * or ejb.xml).
         *
         * @param metadata the metadata file location
         *
         * @return itself
         */
        public Builder addMetadata(String name, File metadata) {
            if (!metadata.exists()) {
                throw new IllegalArgumentException(metadata.getAbsolutePath() + " not found");
            }
            this.metadata.put(name, metadata);
            return this;
        }

        /**
         * Adds a directory to the classes classpath. Will be used to retrieve requested .class
         * files.
         *
         * @param location must be a directory location
         * @return itself
         */
        public Builder addClassPath(File location) {
            if (!location.isDirectory()) {
                throw new IllegalArgumentException("location is not a directory");
            }
            try {
                this.urls.add(location.toURI().toURL());
            } catch (MalformedURLException e) {
                throw new IllegalArgumentException(e);
            }
            return this;
        }

        /**
         * Adds a URL for the classes classpath. Will be used to retrieve requested .class files
         *
         * @param classpath the new classpath element.
         * @return itself
         */

        public Builder addClassPath(URL classpath) {
            this.urls.add(classpath);
            return this;
        }

        /**
         * Creates a new scattered jar file using this builder instance configuration.
         * The resulting instance will behave like a jar file when introspected by the
         * embedded instance.
         *
         * @return new scattered instance jar file
         */
        public ScatteredArchive buildJar() {
            return new ScatteredArchive(this, Builder.type.jar);
        }

        /**
         * Creates a new scattered war file using this builder instance configuration.
         * The resulting instance will behave like a war file when introspected by the
         * embedded instance.
         *
         * @return the scattered instance war file
         */
        public ScatteredArchive buildWar() {
            return new ScatteredArchive(this, Builder.type.war);
        }

        /**
         * Supported types of scattered archives.
         */
        public enum type {
            jar, war
        }
    }

    final String name;
    final File topDir;
    final File resources;
    final List urls = new ArrayList();
    final Map metadata = new HashMap();
    final Builder.type type;
    final String prefix;

    private ScatteredArchive(Builder builder, Builder.type type) {
        name = builder.name;
        topDir = builder.topDir;
        resources = builder.resources;
        urls.addAll(builder.urls);
        if (topDir!=null && type!=Builder.type.war) {
            try {
                urls.add(topDir.toURI().toURL());
            } catch (MalformedURLException ignore) {

            }
        }
        metadata.putAll(builder.metadata);
        this.type = type;
        prefix = type==Builder.type.war?"WEB-INF/classes":null;
    }

    // todo : look at Open(URI), is it ok ?

    /**
     * Get the classpath URLs
     *
     * @return A read-only copy of the classpath URL Collection
     */
    public Iterable getClassPath() {
        return Collections.unmodifiableCollection(urls);
    }

    /**
     * @return The resources directory
     */
    public File getResourcesDir() {
        return resources;
    }

    /**
     * Returns the InputStream for the given entry name
     * The file name must be relative to the root of the module.
     *
     * @param arg the file name relative to the root of the module.
     * @return the InputStream for the given entry name or null if not found.
     */

    public InputStream getEntry(String arg) throws IOException {
        File f = getFile(arg);
        if (f!=null && f.exists()) return new FileInputStream(f);
        JarFile jar = getJarWithEntry(arg);
        if (jar != null) {
            ZipEntry entry = jar.getEntry(arg);
            if (entry != null) {
                return jar.getInputStream(entry);
            }
        }
        return null;
    }

    @Override
    public long getEntrySize(String arg) {
        File f = getFile(arg);
        if (f!=null && f.exists()) return f.length();
        JarFile jar = getJarWithEntry(arg);
        if (jar != null) {
            ZipEntry entry = jar.getEntry(arg);
            if (entry != null) {
                return jar.getEntry(arg).getSize();
            }
        }
        return 0L;
    }

    /**
     * Returns whether or not a file by that name exists
     * The file name must be relative to the root of the module.
     *
     * @param name the file name relative to the root of the module.
     * @return does the file exist?
     */


    public boolean exists(String name) throws IOException {
        if ("WEB-INF".equals(name) && type == Builder.type.war) {
            return true;
        }
        return getEntry(name) != null;
    }

    /**
     * Returns an enumeration of the module file entries.  All elements
     * in the enumeration are of type String.  Each String represents a
     * file name relative to the root of the module.
     * 

Currently under construction * * @return an enumeration of the archive file entries. */ public Enumeration entries() { // TODO: abstraction breakage. We need file-level abstraction for archive // and then more structured abstraction. Vector entries = new Vector(); File localResources = resources; for (URL url : urls) { try { if (localResources!=null && localResources.toURI().toURL().sameFile(url)) { localResources=null; } File f; try { f = new File(url.toURI()); } catch(URISyntaxException e) { f = new File(url.getPath()); } if (f.isFile()) { try (JarFile jar = new JarFile(f)) { Enumeration jarEntries = jar.entries(); while (jarEntries.hasMoreElements()) { JarEntry jarEntry = jarEntries.nextElement(); if (jarEntry.isDirectory()) { continue; } entries.add(jarEntry.getName()); } } } else { getListOfFiles(f, prefix, entries); } } catch (Exception e) { e.printStackTrace(); } } if (localResources!=null) { getListOfFiles(localResources, null, entries); } return entries.elements(); } private void getListOfFiles(File directory, String prefix, List list) { if (!directory.isDirectory()) return; File[] files = directory.listFiles(); if (files != null) { for (File file : files) { String name = prefix == null ? file.getName() : prefix + "/" + file.getName(); if (file.isDirectory()) { getListOfFiles(file, name ,list); } else { list.add(name); } } } } /** * Returns the manifest information for this archive * * @return the manifest info */ public Manifest getManifest() throws IOException { InputStream is = getEntry(JarFile.MANIFEST_NAME); if (is != null) { try { return new Manifest(is); } finally { is.close(); } } return new Manifest(); } /** * Returns the path used to create or open the underlying archive *

*

* TODO: abstraction breakage: * Several callers, most notably {@link org.glassfish.api.deployment.DeploymentContext#getSourceDir()} * implementation, assumes that this URI is an URL, and in fact file URL. *

*

* If this needs to be URL, use of {@link URI} is misleading. And furthermore, * if its needs to be a file URL, this should be {@link File}. * * @return the path for this archive. */ public URI getURI() { if (topDir != null) { return topDir.toURI(); } if (resources != null) { return resources.toURI(); } try { //TODO : Fix this if (urls.size() > 0) { for (URL url : urls) { File f = new File(url.toURI()); if (f.isFile()) return url.toURI(); } return urls.get(0).toURI(); } return null; } catch (Exception e) { return null; } } /** * Returns the name of the archive. *

* Implementations should not return null. * * @return the name of the archive */ public String getName() { return name; } /** * Returns the archive type * @return the archive type */ public Builder.type type() { return type; } /** * Returns an enumeration of the module file entries with the * specified prefix. All elements in the enumeration are of * type String. Each String represents a file name relative * to the root of the module. *

Currently Not Supported * * @param s the prefix of entries to be included * @return an enumeration of the archive file entries. */ public Enumeration entries(String s) { Enumeration entries = entries(); Vector prefixedEntries = new Vector(); while (entries.hasMoreElements()) { String entry = (String)entries.nextElement(); if (entry.startsWith(s)) prefixedEntries.add(entry); } return prefixedEntries.elements(); } @Override public Collection getDirectories() throws IOException { return new ArrayList(); } public String toString() { return super.toString() + " located at " + (topDir == null ? resources : topDir); } public File getFile(String name) { if (metadata.containsKey(name)) { return metadata.get(name); } String shortName = (name.indexOf('/') != -1 ? name.substring(name.indexOf('/') + 1) : name); if (metadata.containsKey(shortName)) { return metadata.get(shortName); } if (resources != null) { File f = new File(resources, name); if (f.exists()) { return f; } } if (prefix!=null) { if (name.startsWith(prefix)) { name = name.substring(prefix.length()+1); } } for (URL url : urls) { File f = null; try { f = new File(url.toURI()); } catch(URISyntaxException e) { f = new File(url.getPath()); } f = new File(f, name); if (f.exists()) { return f; } } return null; } private JarFile getJarWithEntry(String name) { for (URL url : urls) { File f; try { f = new File(url.toURI()); } catch(URISyntaxException e) { f = new File(url.getPath()); } try { if (f.getName().endsWith(".jar")) { JarFile jar = new JarFile(f); if (jar.getEntry(name) != null) { return jar; } else { jar.close(); } } } catch (Exception ex) { ex.printStackTrace(); return null; } } return null; } @Override public void close() throws IOException { } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy