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