alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (ScatteredArchive.java)

This example Glassfish source code file (ScatteredArchive.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

arraylist, builder, builder, enumeration, file, file, io, ioexception, jar, jarfile, jarfile, net, network, scatteredarchive, string, string, url, util, vector, zip

The Glassfish ScatteredArchive.java source code

/*
 * 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<URL> urls = new ArrayList();
        final Map<String, File> 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<URL> 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<URL> urls = new ArrayList();
    final Map<String, File> 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<URL> 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.
     * <p>Currently under construction
     *
     * @return an enumeration of the archive file entries.
     */
    public Enumeration<String> entries() {
        // TODO: abstraction breakage. We need file-level abstraction for archive
        // and then more structured abstraction.

        Vector<String> 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()) {
                    JarFile jar = new JarFile(f);
                    Enumeration<JarEntry> 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<String> list) {
        if (!directory.isDirectory())
            return;
        for (File f : directory.listFiles()) {
            String name = prefix==null?f.getName():prefix+"/"+f.getName();
            if (f.isDirectory()) {
                getListOfFiles(f, 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
     * <p/>
     * <p/>
     * 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.
     * <p/>
     * <p/>
     * 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.
     * <p/>
     * 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.
     * <p>Currently Not Supported
     *
     * @param s the prefix of entries to be included
     * @return an enumeration of the archive file entries.
     */

    public Enumeration<String> entries(String s) {
        Enumeration <String> entries = entries();
        Vector<String> prefixedEntries = new Vector();
        while (entries.hasMoreElements()) {
            String entry = (String)entries.nextElement();
            if (entry.startsWith(s))
                prefixedEntries.add(entry);
        }
        return prefixedEntries.elements();
    }

    @Override
    public Collection<String> getDirectories() throws IOException {
        return new ArrayList<String>();
    }

    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 = null;
            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;
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
                return null;
            }
        }
        return null;
    }

   @Override
   public void close() throws IOException {
   }

}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish ScatteredArchive.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.