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
015package org.apache.tapestry.services.impl;
016
017import java.util.Collections;
018import java.util.HashMap;
019import java.util.Map;
020
021import org.apache.commons.logging.Log;
022import org.apache.hivemind.ClassResolver;
023import org.apache.hivemind.service.ClassFactory;
024import org.apache.hivemind.util.Defense;
025import org.apache.tapestry.enhance.EnhancedClassValidator;
026import org.apache.tapestry.enhance.EnhancementOperationImpl;
027import org.apache.tapestry.enhance.EnhancementWorker;
028import org.apache.tapestry.event.ReportStatusEvent;
029import org.apache.tapestry.event.ReportStatusListener;
030import org.apache.tapestry.event.ResetEventListener;
031import org.apache.tapestry.services.ComponentConstructor;
032import org.apache.tapestry.services.ComponentConstructorFactory;
033import 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 */
042public 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}