    001    // Copyright 2006, 2007, 2008 The Apache Software Foundation
    002    //
    003    // Licensed under the Apache License, Version 2.0 (the "License");
    004    // you may not use this file except in compliance with the License.
    005    // You may obtain a copy of the License at
    006    //
    007    //     http://www.apache.org/licenses/LICENSE-2.0
    008    //
    009    // Unless required by applicable law or agreed to in writing, software
    010    // distributed under the License is distributed on an "AS IS" BASIS,
    011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012    // See the License for the specific language governing permissions and
    013    // limitations under the License.
    014
    015    package org.apache.tapestry5.ioc;
    016
    017    import static org.apache.tapestry5.ioc.IOCConstants.MODULE_BUILDER_MANIFEST_ENTRY_NAME;
    018    import org.apache.tapestry5.ioc.annotations.SubModule;
    019    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    020
    021    import java.io.Closeable;
    022    import java.io.IOException;
    023    import java.io.InputStream;
    024    import java.net.URL;
    025    import java.util.Enumeration;
    026    import java.util.jar.Manifest;
    027
    028    /**
    029     * A collection of utility methods for a couple of different areas, including creating the initial {@link
    030     * org.apache.tapestry5.ioc.Registry}.
    031     */
    032    public final class IOCUtilities
    033    {
    034        private IOCUtilities()
    035        {
    036        }
    037
    038        /**
    039         * Construct a default Registry, including modules identifed via the Tapestry-Module-Classes Manifest entry. The
    040         * registry will have been {@linkplain Registry#performRegistryStartup() started up} before it is returned.
    041         *
    042         * @return constructed Registry, after startup
    043         * @see #addDefaultModules(RegistryBuilder)
    044         */
    045        public static Registry buildDefaultRegistry()
    046        {
    047            RegistryBuilder builder = new RegistryBuilder();
    048
    049            addDefaultModules(builder);
    050
    051            Registry registry = builder.build();
    052
    053            registry.performRegistryStartup();
    054
    055            return registry;
    056        }
    057
    058        /**
    059         * Scans the classpath for JAR Manifests that contain the Tapestry-Module-Classes attribute and adds each
    060         * corresponding class to the RegistryBuilder. In addition, looks for a system property named "tapestry.modules" and
    061         * adds all of those modules as well. The tapestry.modules approach is intended for development.
    062         *
    063         * @param builder the builder to which modules will be added
    064         * @see SubModule
    065         * @see RegistryBuilder#add(String)
    066         */
    067        public static void addDefaultModules(RegistryBuilder builder)
    068        {
    069            try
    070            {
    071                Enumeration<URL> urls = builder.getClassLoader().getResources("META-INF/MANIFEST.MF");
    072
    073                while (urls.hasMoreElements())
    074                {
    075                    URL url = urls.nextElement();
    076
    077                    addModulesInManifest(builder, url);
    078                }
    079
    080                addModulesInList(builder, System.getProperty("tapestry.modules"));
    081
    082            }
    083            catch (IOException ex)
    084            {
    085                throw new RuntimeException(ex.getMessage(), ex);
    086            }
    087        }
    088
    089        private static void addModulesInManifest(RegistryBuilder builder, URL url)
    090        {
    091            InputStream in = null;
    092
    093            Throwable fail = null;
    094
    095            try
    096            {
    097                in = url.openStream();
    098
    099                Manifest mf = new Manifest(in);
    100
    101                in.close();
    102
    103                in = null;
    104
    105                String list = mf.getMainAttributes().getValue(MODULE_BUILDER_MANIFEST_ENTRY_NAME);
    106
    107                addModulesInList(builder, list);
    108            }
    109            catch (RuntimeException ex)
    110            {
    111                fail = ex;
    112            }
    113            catch (IOException ex)
    114            {
    115                fail = ex;
    116            }
    117            finally
    118            {
    119                close(in);
    120            }
    121
    122            if (fail != null)
    123                throw new RuntimeException(String.format("Exception loading module(s) from manifest %s: %s",
    124                                                         url.toString(),
    125                                                         InternalUtils.toMessage(fail)), fail);
    126
    127        }
    128
    129        static void addModulesInList(RegistryBuilder builder, String list)
    130        {
    131            if (list == null) return;
    132
    133            String[] classnames = list.split(",");
    134
    135            for (String classname : classnames)
    136            {
    137                builder.add(classname.trim());
    138            }
    139        }
    140
    141        /**
    142         * Closes an input stream (or other Closeable), ignoring any exception.
    143         *
    144         * @param closeable the thing to close, or null to close nothing
    145         */
    146        private static void close(Closeable closeable)
    147        {
    148            if (closeable != null)
    149            {
    150                try
    151                {
    152                    closeable.close();
    153                }
    154                catch (IOException ex)
    155                {
    156                    // Ignore.
    157                }
    158            }
    159        }
    160    }