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        if (log.isDebugEnabled())
070        {
071            log.debug("Class Fragment is " + name);
072        }
073
074        if (StringUtils.isNotEmpty(name))
075        {
076            for (String p : packages)
077            {
078                StringBuilder sb = new StringBuilder();
079
080                sb.append(p).append('.').append(packageName).append('.').append(name);
081                String className = sb.toString();
082
083                if (log.isDebugEnabled())
084                {
085                    log.debug("Trying " + className);
086                }
087
088                try
089                {
090                    Class<T> servClass = classCache.get(className);
091                    if (servClass == null)
092                    {
093                        servClass = (Class<T>) Class.forName(className);
094                        Class<T> _servClass = classCache.putIfAbsent(className, servClass);
095                        if (_servClass != null)
096                        {
097                            servClass = _servClass;
098                        }
099                    }
100                    assembler = servClass.newInstance();
101                    break; // for()
102                }
103                catch (ClassNotFoundException cnfe)
104                {
105                    // Do this so we loop through all the packages.
106                    log.debug(className + ": Not found");
107                }
108                catch (NoClassDefFoundError ncdfe)
109                {
110                    // Do this so we loop through all the packages.
111                    log.debug(className + ": No Class Definition found");
112                }
113                catch (ClassCastException cce)
114                {
115                    // This means trouble!
116                    // Alternatively we can throw this exception so
117                    // that it will appear on the client browser
118                    log.error("Could not load "+className, cce);
119                    break; // for()
120                }
121                catch (InstantiationException ine)
122                {
123                    // This means trouble!
124                    // Alternatively we can throw this exception so
125                    // that it will appear on the client browser
126                    log.error("Could not load "+className, ine);
127                    break; // for()
128                }
129                catch (IllegalAccessException ilae)
130                {
131                    // This means trouble!
132                    // Alternatively we can throw this exception so
133                    // that it will appear on the client browser
134                    log.error("Could not load "+className, ilae);
135                    break; // for()
136                }
137                // With ClassCastException, InstantiationException we hit big problems
138            }
139        }
140
141        if (log.isDebugEnabled())
142        {
143            log.debug("Returning: " + assembler);
144        }
145
146        return assembler;
147    }
148
149    /**
150     * Get the loader for this type of assembler
151     *
152     * @return a Loader
153     */
154    @Override
155    public abstract Loader<T> getLoader();
156
157    /**
158     * Get the size of a possibly configured cache
159     *
160     * @return the size of the cache in bytes
161     */
162    @Override
163    public int getCacheSize()
164    {
165        return getLoader().getCacheSize();
166    }
167}