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