    001    /*****************************************************************************
    002     * Copyright (C) NanoContainer Organization. All rights reserved.            *
    003     * ------------------------------------------------------------------------- *
    004     * The software in this package is published under the terms of the BSD      *
    005     * style license a copy of which has been included with this distribution in *
    006     * the LICENSE.txt file.                                                     *
    007     *                                                                           *
    008     *****************************************************************************/
    009
    010    package org.nanocontainer.script;
    011
    012    import java.io.File;
    013    import java.net.URL;
    014    import java.util.HashMap;
    015    import java.util.Map;
    016
    017    /**
    018     * ScriptBuilderResolver handles the task of resolving a file name to a builder
    019     * name.  Typical default resolution is for Groovy, BeanShell, JavaScript,
    020     * Jython, and XML script names.  However, you can register/replace your
    021     * own builder implementations by using the registerBuilder() function.
    022     * @author Michael Rimov
    023     */
    024    public class ScriptBuilderResolver {
    025
    026        public static final String GROOVY = ".groovy";
    027        public static final String BEANSHELL = ".bsh";
    028        public static final String JAVASCRIPT = ".js";
    029        public static final String JYTHON = ".py";
    030        public static final String XML = ".xml";
    031
    032        public static final String DEFAULT_GROOVY_BUILDER = "org.nanocontainer.script.groovy.GroovyContainerBuilder";
    033        public static final String DEFAULT_BEANSHELL_BUILDER = "org.nanocontainer.script.bsh.BeanShellContainerBuilder";
    034        public static final String DEFAULT_JAVASCRIPT_BUILDER = "org.nanocontainer.script.rhino.JavascriptContainerBuilder";
    035        public static final String DEFAULT_XML_BUILDER = "org.nanocontainer.script.xml.XMLContainerBuilder";
    036        public static final String DEFAULT_JYTHON_BUILDER = "org.nanocontainer.script.jython.JythonContainerBuilder";
    037
    038        private final Map extensionToBuilders = new HashMap();
    039
    040
    041
    042        public ScriptBuilderResolver() {
    043            resetBuilders();
    044        }
    045
    046
    047        /**
    048         * Retrieve the classname of the appropriate ScriptedContainerBuilder given the file.
    049         * @param compositionFile File
    050         * @return String
    051         */
    052        public String getBuilderClassName(File compositionFile) {
    053            String language = getExtension(compositionFile.getAbsolutePath());
    054            return getBuilderClassName(language);
    055        }
    056
    057
    058
    059
    060        /**
    061         * Retrieve the classname of the appropriate ScriptedContainerBuilder given the file.
    062         * @param compositionFile File
    063         * @return String
    064         */
    065        public String getBuilderClassName(URL compositionURL) {
    066            String language = getExtension(compositionURL.getFile());
    067            return getBuilderClassName(language);
    068        }
    069
    070        /**
    071         * Retrieve the classname of the builder to use given the provided
    072         * extension.  Example:
    073         * <code><pre>
    074         * ScriptedContainerBuilderFactory factory = new ScriptedContainerBuilderFactory(.....);
    075         * String groovyBuilderName = factory.getBuilderClassName(&quot;.groovy&quot;);
    076         * assert &quot;org.nanocontainer.script.groovy.GroovyContainerBuilder&quot;.equals(groovyBuilderName);
    077         * </pre></code>
    078         * @param extension String
    079         * @return String
    080         */
    081        public synchronized String getBuilderClassName(final String extension) throws UnsupportedScriptTypeException{
    082            String resultingBuilderClassName = null;
    083            resultingBuilderClassName = (String) extensionToBuilders.get(extension);
    084            if (resultingBuilderClassName == null) {
    085                throw new UnsupportedScriptTypeException(extension, this.getAllSupportedExtensions());
    086            }
    087            return resultingBuilderClassName;
    088        }
    089
    090        /**
    091         * Function to allow the resetting of the builder map to defaults.  Allows
    092         * testing of the static resource a bit better.
    093         */
    094        public synchronized void resetBuilders() {
    095            extensionToBuilders.clear();
    096
    097            //This is a bit clunky compared to just registering the items
    098            //directly into the map, but this way IMO it provides a single access
    099            //point into the extensionToBuilders map.
    100            registerBuilder(GROOVY, DEFAULT_GROOVY_BUILDER);
    101            registerBuilder(BEANSHELL, DEFAULT_BEANSHELL_BUILDER);
    102            registerBuilder(JAVASCRIPT, DEFAULT_JAVASCRIPT_BUILDER);
    103            registerBuilder(XML, DEFAULT_XML_BUILDER);
    104            registerBuilder(JYTHON, DEFAULT_JYTHON_BUILDER);
    105
    106        }
    107
    108        /**
    109         * Registers/replaces a new handler for a given extension.  Allows for customizable
    110         * behavior in the various builders or the possibility to dynamically add
    111         * handlers for new file types.  Example:
    112         * <code><pre>
    113         * ScriptedContainerBuilderFactory factory = new ScriptedContainerBuilderFactory(...)
    114         * factory.registerBuilder(&quot;.groovy&quot;, &quot;org.nanocontainer.script.groovy.GroovyContainerBuilder&quot;);
    115         * ScriptedContainerBuilder builder = factory.getContainerBuilder();
    116         * assertNotNull(builder);
    117         * </pre></code>
    118         * <p>The internal code now requires synchronization of the builder extension map since
    119         * who knows what is using it when a new builder is registered.</p>
    120         * @param extension String the extension to register under.
    121         * @param className String the classname to use for the given extension.
    122         */
    123        public synchronized void registerBuilder(final String extension, final String className) {
    124            extensionToBuilders.put(extension, className);
    125        }
    126
    127        /**
    128         * Retrieve a list of all supported extensions.
    129         * @return String[] of extensions including the period in the name.
    130         */
    131        public synchronized String[] getAllSupportedExtensions() {
    132             return (String[]) extensionToBuilders.keySet().toArray(new String[extensionToBuilders.size()]);
    133        }
    134
    135
    136        /**
    137         * Retrieve the extension of the file name.
    138         * @param fileName String
    139         * @return String
    140         */
    141        private String getExtension(String fileName) {
    142            return fileName.substring(fileName.lastIndexOf("."));
    143        }
    144
    145
    146    }