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.HashMap;
018import java.util.Map;
019
020import org.apache.hivemind.ApplicationRuntimeException;
021import org.apache.hivemind.ClassResolver;
022import org.apache.hivemind.Resource;
023import org.apache.hivemind.util.ClasspathResource;
024import org.apache.tapestry.INamespace;
025import org.apache.tapestry.asset.AssetSource;
026import org.apache.tapestry.engine.ISpecificationSource;
027import org.apache.tapestry.engine.Namespace;
028import org.apache.tapestry.event.ReportStatusEvent;
029import org.apache.tapestry.event.ReportStatusListener;
030import org.apache.tapestry.event.ResetEventListener;
031import org.apache.tapestry.parse.ISpecificationParser;
032import org.apache.tapestry.services.NamespaceResources;
033import org.apache.tapestry.spec.IApplicationSpecification;
034import org.apache.tapestry.spec.IComponentSpecification;
035import org.apache.tapestry.spec.ILibrarySpecification;
036import org.apache.tapestry.spec.LibrarySpecification;
037import org.apache.tapestry.util.xml.DocumentParseException;
038
039/**
040 * Default implementation of {@link ISpecificationSource} that expects to use the normal class
041 * loader to locate component specifications from within the classpath.
042 * <p>
043 * Caches specifications in memory forever, or until {@link #resetDidOccur()} is invoked.
044 * 
045 * @author Howard Lewis Ship
046 */
047public class SpecificationSourceImpl implements ISpecificationSource, ResetEventListener,
048        ReportStatusListener
049{
050    private ClassResolver _classResolver;
051
052    private IApplicationSpecification _specification;
053
054    private ISpecificationParser _parser;
055
056    private NamespaceResources _namespaceResources;
057
058    private INamespace _applicationNamespace;
059
060    private INamespace _frameworkNamespace;
061
062    private AssetSource _assetSource;
063
064    private String _serviceId;
065
066    /**
067     * Contains previously parsed component specifications.
068     */
069
070    private Map _componentCache = new HashMap();
071
072    /**
073     * Contains previously parsed page specifications.
074     * 
075     * @since 2.2
076     */
077
078    private Map _pageCache = new HashMap();
079
080    /**
081     * Contains previously parsed library specifications, keyed on specification resource path.
082     * 
083     * @since 2.2
084     */
085
086    private Map _libraryCache = new HashMap();
087
088    /**
089     * Contains {@link INamespace} instances, keyed on id (which will be null for the application
090     * specification).
091     */
092
093    private Map _namespaceCache = new HashMap();
094
095    public void reportStatus(ReportStatusEvent event)
096    {
097        event.title(_serviceId);
098
099        event.property("page specification count", _pageCache.size());
100        event.collection("page specifications", _pageCache.keySet());
101        event.property("component specification count", _componentCache.size());
102        event.collection("component specifications", _componentCache.keySet());
103    }
104
105    public void initializeService()
106    {
107        _namespaceResources = new NamespaceResourcesImpl(this, _assetSource);
108    }
109
110    /**
111     * Clears the specification cache. This is used during debugging.
112     */
113
114    public synchronized void resetEventDidOccur()
115    {
116        _componentCache.clear();
117        _pageCache.clear();
118        _libraryCache.clear();
119        _namespaceCache.clear();
120
121        _applicationNamespace = null;
122        _frameworkNamespace = null;
123    }
124
125    protected IComponentSpecification parseSpecification(Resource resource, boolean asPage)
126    {
127        IComponentSpecification result = null;
128
129        try
130        {
131            if (asPage)
132                result = _parser.parsePageSpecification(resource);
133            else
134                result = _parser.parseComponentSpecification(resource);
135        }
136        catch (DocumentParseException ex)
137        {
138            throw new ApplicationRuntimeException(
139                    ImplMessages.unableToParseSpecification(resource), ex);
140        }
141
142        return result;
143    }
144
145    protected ILibrarySpecification parseLibrarySpecification(Resource resource)
146    {
147        try
148        {
149            return _parser.parseLibrarySpecification(resource);
150        }
151        catch (DocumentParseException ex)
152        {
153            throw new ApplicationRuntimeException(
154                    ImplMessages.unableToParseSpecification(resource), ex);
155        }
156
157    }
158
159    /**
160     * Gets a component specification.
161     * 
162     * @param resourcePath
163     *            the complete resource path to the specification.
164     * @throws ApplicationRuntimeException
165     *             if the specification cannot be obtained.
166     */
167
168    public synchronized IComponentSpecification getComponentSpecification(Resource resourceLocation)
169    {
170        IComponentSpecification result = (IComponentSpecification) _componentCache
171                .get(resourceLocation);
172
173        if (result == null)
174        {
175            result = parseSpecification(resourceLocation, false);
176
177            _componentCache.put(resourceLocation, result);
178        }
179
180        return result;
181    }
182
183    public synchronized IComponentSpecification getPageSpecification(Resource resourceLocation)
184    {
185        IComponentSpecification result = (IComponentSpecification) _pageCache.get(resourceLocation);
186
187        if (result == null)
188        {
189            result = parseSpecification(resourceLocation, true);
190
191            _pageCache.put(resourceLocation, result);
192        }
193
194        return result;
195    }
196
197    public synchronized ILibrarySpecification getLibrarySpecification(Resource resourceLocation)
198    {
199        ILibrarySpecification result = (LibrarySpecification) _libraryCache.get(resourceLocation);
200
201        if (result == null)
202        {
203            result = parseLibrarySpecification(resourceLocation);
204            _libraryCache.put(resourceLocation, result);
205        }
206
207        return result;
208    }
209
210    public synchronized INamespace getApplicationNamespace()
211    {
212        if (_applicationNamespace == null)
213            _applicationNamespace = new Namespace(null, null, _specification, _namespaceResources);
214
215        return _applicationNamespace;
216    }
217
218    public synchronized INamespace getFrameworkNamespace()
219    {
220        if (_frameworkNamespace == null)
221        {
222            Resource resource = new ClasspathResource(_classResolver,
223                    "/org/apache/tapestry/Framework.library");
224
225            ILibrarySpecification ls = getLibrarySpecification(resource);
226
227            _frameworkNamespace = new Namespace(INamespace.FRAMEWORK_NAMESPACE, null, ls,
228                    _namespaceResources);
229        }
230
231        return _frameworkNamespace;
232    }
233
234    public void setParser(ISpecificationParser parser)
235    {
236        _parser = parser;
237    }
238
239    public void setClassResolver(ClassResolver resolver)
240    {
241        _classResolver = resolver;
242    }
243
244    public void setSpecification(IApplicationSpecification specification)
245    {
246        _specification = specification;
247    }
248
249    public void setAssetSource(AssetSource assetSource)
250    {
251        _assetSource = assetSource;
252    }
253
254    public void setServiceId(String serviceId)
255    {
256        _serviceId = serviceId;
257    }
258
259}