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 }