001    // Copyright 2004, 2005 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.tapestry.services.impl;
016    
017    import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
018    import org.apache.commons.logging.Log;
019    import org.apache.hivemind.ApplicationRuntimeException;
020    import org.apache.hivemind.ClassResolver;
021    import org.apache.hivemind.service.ClassFactory;
022    import org.apache.hivemind.util.Defense;
023    import org.apache.tapestry.enhance.EnhancedClassValidator;
024    import org.apache.tapestry.enhance.EnhancementOperationImpl;
025    import org.apache.tapestry.enhance.EnhancementWorker;
026    import org.apache.tapestry.event.ReportStatusEvent;
027    import org.apache.tapestry.event.ReportStatusListener;
028    import org.apache.tapestry.event.ResetEventListener;
029    import org.apache.tapestry.services.ComponentConstructor;
030    import org.apache.tapestry.services.ComponentConstructorFactory;
031    import org.apache.tapestry.spec.IComponentSpecification;
032    
033    import java.util.Collections;
034    import java.util.HashMap;
035    import java.util.Map;
036    
037    /**
038     * Implementation of the {@link org.apache.tapestry.services.ComponentConstructorFactory} service
039     * interface.
040     *
041     * @author Howard M. Lewis Ship
042     * @since 4.0
043     */
044    public class ComponentConstructorFactoryImpl implements ComponentConstructorFactory,
045                                                            ResetEventListener, ReportStatusListener
046    {
047        private final ReentrantLock _lock = new ReentrantLock();
048    
049        private String _serviceId;
050    
051        private Log _log;
052    
053        private ClassFactory _classFactory;
054    
055        private ClassResolver _classResolver;
056    
057        private EnhancedClassValidator _validator;
058    
059        private EnhancementWorker _chain;
060    
061        /**
062         * Map of {@link org.apache.tapestry.services.ComponentConstructor} keyed on
063         * {@link org.apache.tapestry.spec.IComponentSpecification}.
064         */
065    
066        private Map _cachedConstructors = Collections.synchronizedMap(new HashMap());
067    
068        public void resetEventDidOccur()
069        {
070            _cachedConstructors.clear();
071        }
072    
073        public synchronized void reportStatus(ReportStatusEvent event)
074        {
075            event.title(_serviceId);
076    
077            event.property("enhanced class count", _cachedConstructors.size());
078            event.collection("enhanced classes", _cachedConstructors.keySet());
079        }
080    
081        public ComponentConstructor getComponentConstructor(IComponentSpecification specification,
082                                                            String className)
083        {
084            Defense.notNull(specification, "specification");
085    
086            try
087            {
088                _lock.lockInterruptibly();
089    
090                ComponentConstructor result = (ComponentConstructor) _cachedConstructors.get(specification);
091    
092                if (result == null)
093                {
094                    Class baseClass = _classResolver.findClass(className);
095    
096                    EnhancementOperationImpl eo = new EnhancementOperationImpl(_classResolver, specification, baseClass, _classFactory, _log);
097    
098                    // Invoking on the chain is the same as invoking on every
099                    // object in the chain (because method performEnhancement() is type void).
100    
101                    _chain.performEnhancement(eo, specification);
102    
103                    result = eo.getConstructor();
104    
105                    // TODO: This should be optional to work around that IBM JVM bug.
106    
107                    _validator.validate(baseClass, result.getComponentClass(), specification);
108    
109                    _cachedConstructors.put(specification, result);
110                }
111    
112                return result;
113    
114            } catch (InterruptedException e)
115            {
116                throw new ApplicationRuntimeException(e);
117            } finally
118            {
119                _lock.unlock();
120            }
121        }
122    
123        public void setClassFactory(ClassFactory classFactory)
124        {
125            _classFactory = classFactory;
126        }
127    
128        public void setClassResolver(ClassResolver classResolver)
129        {
130            _classResolver = classResolver;
131        }
132    
133        public void setValidator(EnhancedClassValidator validator)
134        {
135            _validator = validator;
136        }
137    
138        public void setChain(EnhancementWorker chain)
139        {
140            _chain = chain;
141        }
142    
143        public void setLog(Log log)
144        {
145            _log = log;
146        }
147    
148        public void setServiceId(String serviceId)
149        {
150            _serviceId = serviceId;
151        }
152    }