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.ReportStatusEvent;
029 import org.apache.tapestry.event.ReportStatusListener;
030 import org.apache.tapestry.event.ResetEventListener;
031 import org.apache.tapestry.parse.ISpecificationParser;
032 import org.apache.tapestry.services.NamespaceResources;
033 import org.apache.tapestry.spec.IApplicationSpecification;
034 import org.apache.tapestry.spec.IComponentSpecification;
035 import org.apache.tapestry.spec.ILibrarySpecification;
036 import org.apache.tapestry.spec.LibrarySpecification;
037 import 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 #resetEventDidOccur()} is invoked.
044 *
045 * @author Howard Lewis Ship
046 */
047 public 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 resourceLocation
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 }