001: // Copyright 2006, 2007 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.internal.services;
016:
017: import java.io.File;
018: import java.net.MalformedURLException;
019: import java.net.URL;
020: import java.net.URLClassLoader;
021: import java.util.Locale;
022: import java.util.UUID;
023:
024: import org.apache.tapestry.internal.InternalConstants;
025: import org.apache.tapestry.internal.events.InvalidationListener;
026: import org.apache.tapestry.internal.parser.ComponentTemplate;
027: import org.apache.tapestry.internal.test.InternalBaseTestCase;
028: import org.apache.tapestry.ioc.Resource;
029: import org.apache.tapestry.ioc.internal.util.ClasspathResource;
030: import org.apache.tapestry.model.ComponentModel;
031: import org.testng.annotations.Test;
032:
033: public class ComponentTemplateSourceImplTest extends
034: InternalBaseTestCase {
035: private static final String PACKAGE = "org.apache.tapestry.internal.pageload";
036:
037: static public final String PATH = "org/apache/tapestry/internal/pageload";
038:
039: private final ClassLoader _loader = Thread.currentThread()
040: .getContextClassLoader();
041:
042: /**
043: * Creates a new class loader, whose parent is the thread's context class loader, but adds a
044: * single classpath root from the filesystem.
045: *
046: * @see #createClasspathRoot()
047: */
048: protected final URLClassLoader newLoaderWithClasspathRoot(
049: File rootDir) throws MalformedURLException {
050: String urlPath = rootDir.toURL().toString();
051: // URLs for folders must end with a slash to make URLClassLoader happy.
052: URL url = new URL(urlPath + "/");
053:
054: return new URLClassLoader(new URL[] { url }, _loader);
055: }
056:
057: /**
058: * Creates a new temporary directory which can act as a classpath root.
059: *
060: * @see #newLoaderWithClasspathRoot(File)
061: */
062: protected final File createClasspathRoot() {
063: String temp = System.getProperty("java.io.tmpdir");
064: String rootDirPath = temp + "/" + UUID.randomUUID().toString();
065:
066: return new File(rootDirPath);
067: }
068:
069: @Test
070: public void caching() {
071: Resource baseResource = newResource("Fred.class");
072:
073: TemplateParser parser = mockTemplateParser();
074: ComponentTemplate template = mockComponentTemplate();
075: ComponentModel model = mockComponentModel();
076:
077: train_getComponentClassName(model, PACKAGE + ".Fred");
078:
079: train_getBaseResource(model, baseResource);
080:
081: train_parseTemplate(parser, baseResource
082: .withExtension(InternalConstants.TEMPLATE_EXTENSION),
083: template);
084:
085: replay();
086:
087: ComponentTemplateSource source = new ComponentTemplateSourceImpl(
088: parser, null);
089:
090: assertSame(source.getTemplate(model, Locale.ENGLISH), template);
091:
092: // A second pass will test the caching (the
093: // parser is not invoked).
094:
095: assertSame(source.getTemplate(model, Locale.ENGLISH), template);
096:
097: verify();
098: }
099:
100: /** Tests resource invalidation. */
101: @Test
102: public void invalidation() throws Exception {
103: File rootDir = createClasspathRoot();
104: URLClassLoader loader = newLoaderWithClasspathRoot(rootDir);
105: ComponentModel model = mockComponentModel();
106:
107: File packageDir = new File(rootDir, "baz");
108: packageDir.mkdirs();
109:
110: File f = new File(packageDir, "Biff.html");
111:
112: f.createNewFile();
113:
114: Resource baseResource = new ClasspathResource(loader,
115: "baz/Biff.class");
116: Resource localized = baseResource
117: .withExtension(InternalConstants.TEMPLATE_EXTENSION);
118:
119: TemplateParser parser = mockTemplateParser();
120: ComponentTemplate template = mockComponentTemplate();
121: InvalidationListener listener = mockInvalidationListener();
122:
123: train_getComponentClassName(model, "baz.Biff");
124:
125: train_getBaseResource(model, baseResource);
126:
127: train_parseTemplate(parser, localized, template);
128:
129: replay();
130:
131: ComponentTemplateSourceImpl source = new ComponentTemplateSourceImpl(
132: parser, null);
133: source.addInvalidationListener(listener);
134:
135: assertSame(source.getTemplate(model, Locale.ENGLISH), template);
136:
137: // Check for updates (which won't be found).
138: source.checkForUpdates();
139:
140: // A second pass will test the caching (the
141: // parser is not invoked).
142:
143: assertSame(source.getTemplate(model, Locale.ENGLISH), template);
144:
145: verify();
146:
147: // Now, change the file and process an UpdateEvent.
148:
149: touch(f);
150:
151: listener.objectWasInvalidated();
152:
153: replay();
154:
155: // Check for updates (which will be found).
156: source.checkForUpdates();
157:
158: verify();
159:
160: // Check that the cache really is cleared.
161:
162: train_getComponentClassName(model, "baz.Biff");
163:
164: train_getBaseResource(model, baseResource);
165:
166: train_parseTemplate(parser, localized, template);
167:
168: replay();
169:
170: assertSame(source.getTemplate(model, Locale.ENGLISH), template);
171:
172: verify();
173: }
174:
175: /** Checks that localization to the same resource works (w/ caching). */
176: @Test
177: public void localization_to_same() {
178: Resource baseResource = newResource("Fred.class");
179:
180: TemplateParser parser = mockTemplateParser();
181: ComponentTemplate template = mockComponentTemplate();
182: ComponentModel model = mockComponentModel();
183:
184: train_getComponentClassName(model, PACKAGE + ".Fred");
185:
186: train_getBaseResource(model, baseResource);
187:
188: train_parseTemplate(parser, baseResource
189: .withExtension(InternalConstants.TEMPLATE_EXTENSION),
190: template);
191:
192: replay();
193:
194: ComponentTemplateSourceImpl source = new ComponentTemplateSourceImpl(
195: parser, null);
196:
197: assertSame(source.getTemplate(model, Locale.ENGLISH), template);
198:
199: // A second pass finds the same resource, but using a different
200: // path/locale combination.
201:
202: assertSame(source.getTemplate(model, Locale.FRENCH), template);
203:
204: // A third pass should further demonstrate the caching.
205:
206: assertSame(source.getTemplate(model, Locale.FRENCH), template);
207:
208: verify();
209: }
210:
211: @Test
212: public void page_template_found_in_context() {
213: Resource baseResource = newResource("NotInClasspath.class");
214:
215: // Simpler to do it this way ...
216:
217: Resource contextTemplateResource = newResource("Fred.html");
218:
219: TemplateParser parser = mockTemplateParser();
220: ComponentTemplate template = mockComponentTemplate();
221: ComponentModel model = mockComponentModel();
222: PageTemplateLocator locator = mockPageTemplateLocator();
223: Locale locale = Locale.FRENCH;
224:
225: train_getComponentClassName(model, PACKAGE + ".NotInClasspath");
226:
227: train_getBaseResource(model, baseResource);
228:
229: train_findPageTemplateResource(locator, model, locale,
230: contextTemplateResource);
231:
232: train_parseTemplate(parser, contextTemplateResource, template);
233:
234: replay();
235:
236: ComponentTemplateSourceImpl source = new ComponentTemplateSourceImpl(
237: parser, locator);
238:
239: assertSame(source.getTemplate(model, locale), template);
240:
241: verify();
242: }
243:
244: @Test
245: public void no_template_found() {
246: TemplateParser parser = mockTemplateParser();
247: ComponentModel model = mockComponentModel();
248: PageTemplateLocator locator = mockPageTemplateLocator();
249:
250: Resource baseResource = newResource("Barney.class");
251:
252: train_getComponentClassName(model, PACKAGE + ".Barney");
253:
254: train_getBaseResource(model, baseResource);
255:
256: train_findPageTemplateResource(locator, model, Locale.ENGLISH,
257: null);
258:
259: train_getParentModel(model, null);
260:
261: replay();
262:
263: ComponentTemplateSourceImpl source = new ComponentTemplateSourceImpl(
264: parser, locator);
265:
266: ComponentTemplate template = source.getTemplate(model,
267: Locale.ENGLISH);
268:
269: assertTrue(template.isMissing());
270:
271: verify();
272: }
273:
274: @Test
275: public void child_component_inherits_parent_template() {
276: Resource baseFred = newResource("Fred.class");
277: Resource baseBarney = baseFred.forFile("Barney.class");
278: PageTemplateLocator locator = mockPageTemplateLocator();
279:
280: TemplateParser parser = mockTemplateParser();
281: ComponentTemplate template = mockComponentTemplate();
282: ComponentModel model = mockComponentModel();
283: ComponentModel parentModel = mockComponentModel();
284:
285: train_getComponentClassName(model, PACKAGE + ".Barney");
286:
287: train_getBaseResource(model, baseBarney);
288:
289: train_findPageTemplateResource(locator, model, Locale.ENGLISH,
290: null);
291:
292: train_getParentModel(model, parentModel);
293:
294: train_getBaseResource(parentModel, baseFred);
295:
296: train_parseTemplate(parser, baseFred
297: .withExtension(InternalConstants.TEMPLATE_EXTENSION),
298: template);
299:
300: replay();
301:
302: ComponentTemplateSource source = new ComponentTemplateSourceImpl(
303: parser, locator);
304:
305: assertSame(source.getTemplate(model, Locale.ENGLISH), template);
306:
307: verify();
308: }
309:
310: private Resource newResource(String name) {
311: return new ClasspathResource(_loader, PATH + "/" + name);
312: }
313: }
|