001package org.apache.turbine.services.assemblerbroker.util.java;
002
003
004/*
005 * Licensed to the Apache Software Foundation (ASF) under one
006 * or more contributor license agreements.  See the NOTICE file
007 * distributed with this work for additional information
008 * regarding copyright ownership.  The ASF licenses this file
009 * to you under the Apache License, Version 2.0 (the
010 * "License"); you may not use this file except in compliance
011 * with the License.  You may obtain a copy of the License at
012 *
013 *   http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing,
016 * software distributed under the License is distributed on an
017 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
018 * KIND, either express or implied.  See the License for the
019 * specific language governing permissions and limitations
020 * under the License.
021 */
022
023import java.util.List;
024import java.util.concurrent.ConcurrentHashMap;
025
026import org.apache.commons.lang.StringUtils;
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import org.apache.turbine.modules.Assembler;
030import org.apache.turbine.modules.GenericLoader;
031import org.apache.turbine.modules.Loader;
032import org.apache.turbine.services.assemblerbroker.util.AssemblerFactory;
033
034/**
035 * A screen factory that attempts to load a java class from
036 * the module packages defined in the TurbineResource.properties.
037 *
038 * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
039 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
040 * @param <T> the specialized assembler type
041 */
042public abstract class JavaBaseFactory<T extends Assembler>
043    implements AssemblerFactory<T>
044{
045    /** A vector of packages. */
046    private static List<String> packages = GenericLoader.getPackages();
047
048    /** Logging */
049    protected Log log = LogFactory.getLog(this.getClass());
050
051    /**
052     * A cache for previously obtained Class instances, which we keep in order
053     * to reduce the Class.forName() overhead (which can be sizable).
054     */
055    private final ConcurrentHashMap<String, Class<T>> classCache = new ConcurrentHashMap<String, Class<T>>();
056
057    /**
058     * Get an Assembler.
059     *
060     * @param packageName java package name
061     * @param name name of the requested Assembler
062     * @return an Assembler
063     */
064    @SuppressWarnings("unchecked")
065    public T getAssembler(String packageName, String name)
066    {
067        T assembler = null;
068
069        log.debug("Class Fragment is " + name);
070
071        if (StringUtils.isNotEmpty(name))
072        {
073            for (String p : packages)
074            {
075                StringBuilder sb = new StringBuilder();
076
077                sb.append(p).append('.').append(packageName).append('.').append(name);
078                String className = sb.toString();
079
080                log.debug("Trying " + className);
081
082                try
083                {
084                    Class<T> servClass = classCache.get(className);
085                    if (servClass == null)
086                    {
087                        servClass = (Class<T>) Class.forName(className);
088                        classCache.put(className, servClass);
089                    }
090                    assembler = servClass.newInstance();
091                    break; // for()
092                }
093                catch (ClassNotFoundException cnfe)
094                {
095                    // Do this so we loop through all the packages.
096                    log.debug(className + ": Not found");
097                }
098                catch (NoClassDefFoundError ncdfe)
099                {
100                    // Do this so we loop through all the packages.
101                    log.debug(className + ": No Class Definition found");
102                }
103                catch (ClassCastException cce)
104                {
105                    // This means trouble!
106                    // Alternatively we can throw this exception so
107                    // that it will appear on the client browser
108                    log.error("Could not load "+className, cce);
109                    break; // for()
110                }
111                catch (InstantiationException ine)
112                {
113                    // This means trouble!
114                    // Alternatively we can throw this exception so
115                    // that it will appear on the client browser
116                    log.error("Could not load "+className, ine);
117                    break; // for()
118                }
119                catch (IllegalAccessException ilae)
120                {
121                    // This means trouble!
122                    // Alternatively we can throw this exception so
123                    // that it will appear on the client browser
124                    log.error("Could not load "+className, ilae);
125                    break; // for()
126                }
127                // With ClassCastException, InstantiationException we hit big problems
128            }
129        }
130        log.debug("Returning: " + assembler);
131
132        return assembler;
133    }
134
135    /**
136     * Get the loader for this type of assembler
137     *
138     * @return a Loader
139     */
140    @Override
141    public abstract Loader<T> getLoader();
142
143    /**
144     * Get the size of a possibly configured cache
145     *
146     * @return the size of the cache in bytes
147     */
148    @Override
149    public int getCacheSize()
150    {
151        return getLoader().getCacheSize();
152    }
153}