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