/* * Copyright (c) 2002-2012 Alibaba Group Holding Limited. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.citrus.service.resource; import static com.alibaba.citrus.service.resource.ResourceLoadingService.*; import static com.alibaba.citrus.test.TestEnvStatic.*; import static com.alibaba.citrus.test.TestUtil.*; import static com.alibaba.citrus.util.io.StreamUtil.*; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Set; import com.alibaba.citrus.service.resource.impl.ResourceLoadingServiceImpl; import com.alibaba.citrus.service.resource.support.InputStreamResource; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; public class ResourceLoadingServiceTests extends AbstractResourceLoadingTests { @BeforeClass public static void initClass() throws Exception { initFactory("resources-root.xml"); initSubFactory("WEB-INF/resources.xml"); } @Before public void init() throws Exception { resourceLoadingService = (ResourceLoadingService) factory.getBean("resourceLoadingService"); ResourceLoadingService parentService = (ResourceLoadingService) parentFactory.getBean("resourceLoadingService"); assertSame(parentService, resourceLoadingService.getParent()); } @Test public void notInited() { // 在service初始化过程中,某个loader/filter通过spring resource loader间接递归调用该service时,报错。 try { new ResourceLoadingServiceImpl().getResource("test"); fail(); } catch (IllegalStateException e) { assertThat(e, exception("Bean instance of " + ResourceLoadingService.class.getName() + " has not been initialized yet")); } } @Test public void getResource_emptyName() throws Exception { try { resourceLoadingService.getResource(null); fail(); } catch (IllegalArgumentException e) { assertThat(e, exception("resourceName")); } try { resourceLoadingService.getResource(" "); fail(); } catch (IllegalArgumentException e) { assertThat(e, exception("resourceName")); } } @Test public void service_withParentRef() throws Exception { ResourceLoadingService parentService = (ResourceLoadingService) parentFactory .getBean("myParentResourceLoadingService"); // myResourceLoadingService指定了parentRef=myParentResourceLoadingService resourceLoadingService = (ResourceLoadingService) factory.getBean("myResourceLoadingService"); assertSame(parentService, resourceLoadingService.getParent()); assertResourceService("/default/test.txt", "test.txt", true); } @Test public void service_defaultParentRef() throws Exception { ResourceLoadingService parentService = (ResourceLoadingService) parentFactory .getBean("resourceLoadingService_1"); // resourceLoadingService_1未指定parentRef,但是parent context中包含同名的service resourceLoadingService = (ResourceLoadingService) factory.getBean("resourceLoadingService_1"); assertSame(parentService, resourceLoadingService.getParent()); assertResourceService("/default/test.txt", "test.txt", true); } @Test public void resourceAlias_bySuperLoader() throws Exception { ResourceLoadingService parentService = (ResourceLoadingService) parentFactory .getBean("resourceLoadingService_2"); // resourceLoadingService_2未指定parentRef,但是parent context中包含同名的service resourceLoadingService = (ResourceLoadingService) factory.getBean("resourceLoadingService_2"); assertSame(parentService, resourceLoadingService.getParent()); // /myfolder/testres.txt 映射到<super-loader name="/webroot"> // 和<resource-alias name="/webroot">等效 assertEquals(new File(srcdir, "/myfolder/testres.txt"), resourceLoadingService.getResourceAsFile("/myfolder/testres.txt")); } @Test public void getResource_notFound() throws Exception { try { resourceLoadingService.getResourceAsURL("/not/found.txt"); fail(); } catch (ResourceNotFoundException e) { assertResourceNotFoundException(e, "/not/found.txt", "/webroot/not/found.txt"); } } @Test public void getResource_parent_defaultMapping() throws Exception { // 当前resource loader中没找到,到parent中找,匹配/ assertEquals(new File(srcdir, "/myfolder/testres.txt"), resourceLoadingService.getResourceAsFile("/myfolder/testres.txt")); } @Test public void getResource_alias_notFound() throws Exception { // Alias被匹配,但没找到resource mapping try { resourceLoadingService.getResourceAsURL("/my/alias1/testres.txt"); fail(); } catch (ResourceNotFoundException e) { assertResourceNotFoundException(e, "/my/alias1/testres.txt", "/not/found/testres.txt", "/webroot/not/found/testres.txt"); } } @Test public void getResource_alias_foundInParent() throws Exception { // Alias被匹配,从default resource loader中找到资源 assertEquals(new File(srcdir, "/myfolder/testres.txt"), resourceLoadingService.getResourceAsFile("/my/alias3/testres.txt")); } @Test public void getResource_internal_found() throws Exception { // Alias被匹配,internal mapping被找到 assertEquals(new File(srcdir, "/myfolder/testres.txt"), resourceLoadingService.getResourceAsFile("/my/alias4/testres.txt")); assertEquals(new File(srcdir, "/myfolder/testres.txt"), resourceLoadingService.getParent().getResourceAsFile("/myfolder/testres.txt")); // super-loader被匹配,internal mapping被找到 assertEquals(new File(srcdir, "/myfolder/testres.txt"), resourceLoadingService.getResourceAsFile("/my/alias5/testres.txt")); } @Test public void getResource_internal_notFound() throws Exception { // 直接找internal mapping是不行的 try { resourceLoadingService.getResourceAsURL("/my/internal/resource/testres.txt"); fail(); } catch (ResourceNotFoundException e) { assertResourceNotFoundException(e, "/my/internal/resource/testres.txt", "/webroot/my/internal/resource/testres.txt"); } try { resourceLoadingService.getParent().getResourceAsURL("/webroot/myfolder/testres.txt"); fail(); } catch (ResourceNotFoundException e) { assertResourceNotFoundException(e, "/webroot/myfolder/testres.txt", "/webroot/webroot/myfolder/testres.txt"); } // alias映射到parent internal mapping,这样是不行的 try { resourceLoadingService.getResourceAsURL("/my/alias6/testres.txt"); fail(); } catch (ResourceNotFoundException e) { assertResourceNotFoundException(e, "/my/alias6/testres.txt", "/webroot/myfolder/testres.txt", "/webroot/webroot/myfolder/testres.txt"); } // super-loader映射到parent internal mapping,这样是不行的 try { resourceLoadingService.getResourceAsURL("/my/alias7/testres.txt"); fail(); } catch (ResourceNotFoundException e) { // 由于是loader的方式,故caused by丢失 assertResourceNotFoundException(e, "/my/alias7/testres.txt"/*, "/webroot/myfolder/testres.txt"*/); } } @Test public void getResource_noLoaders() throws Exception { // 匹配,但没有loaders try { resourceLoadingService.getResourceAsURL("/my/resource/testres.txt"); fail(); } catch (ResourceNotFoundException e) { assertResourceNotFoundException(e, "/my/resource/testres.txt"); } } /** 无论resourceName是否以/开始,都可以匹配相应的资源。 */ @Test public void getResource_relativeResourceName() throws Exception { // resource.xml中为相对路径:pattern="relative/resource" assertEquals(new File(srcdir, "/WEB-INF/aaa/bbb/abc.txt"), resourceLoadingService.getResourceAsFile("/relative/resource/abc.txt")); assertEquals(new File(srcdir, "/WEB-INF/aaa/bbb/abc.txt"), resourceLoadingService.getResourceAsFile("relative/resource/abc.txt")); assertEquals(new File(srcdir, "/WEB-INF/aaa/bbb/abc.txt"), resourceLoadingService.getResourceAsFile("aaa/../relative/resource/abc.txt")); // aaa/(relative/resource)/abc.txt => aaa/(aaa/bbb)/abc.txt assertEquals(new File(srcdir, "/WEB-INF/aaa/aaa/bbb/abc.txt"), resourceLoadingService.getResourceAsFile("aaa/relative/resource/abc.txt", FOR_CREATE)); // resource.xml中为绝对路径:pattern="/absolute/resource" assertEquals(new File(srcdir, "/WEB-INF/aaa/bbb/abc.txt"), resourceLoadingService.getResourceAsFile("/absolute/resource/abc.txt")); assertEquals(new File(srcdir, "/WEB-INF/aaa/bbb/abc.txt"), resourceLoadingService.getResourceAsFile("absolute/resource/abc.txt")); try { resourceLoadingService.getResourceAsFile("aaa/absolute/resource/abc.txt"); fail(); } catch (ResourceNotFoundException e) { assertResourceNotFoundException(e, "aaa/absolute/resource/abc.txt", "/webroot/aaa/absolute/resource/abc.txt"); } assertEquals(new File(srcdir, "/WEB-INF/aaa/bbb/abc.txt"), resourceLoadingService.getResourceAsFile("aaa/../absolute/resource/abc.txt")); } @Test public void relevancy() throws Exception { resourceLoadingService = (ResourceLoadingService) factory.getBean("relevancy"); // /aaa/bbb/ccc匹配:/, /aaa/**, /aaa/bbb/ccc, /**, // 但/aaa/bbb/ccc => /dir3最相关 assertEquals(new File(srcdir, "/dir3"), resourceLoadingService.getResourceAsFile("/aaa/bbb/ccc", FOR_CREATE)); // /aaa/bbb/ddd匹配:/, /aaa/**, /** // 但/aaa/** => /dir2最相关 assertEquals(new File(srcdir, "/dir2"), resourceLoadingService.getResourceAsFile("/aaa/bbb/ddd", FOR_CREATE)); // /bbb匹配:/, /** // 但/**的匹配长度较长,故选择/** => /dir4最相关 assertEquals(new File(srcdir, "/dir4"), resourceLoadingService.getResourceAsFile("/bbb", FOR_CREATE)); } @Test public void getResourceAsFile() throws Exception { resourceLoadingService = (ResourceLoadingService) factory.getBean("getResourceAs"); // file存在 File f = new File(srcdir, "/myfolder/testres.txt"); Resource resource = resourceLoadingService.getResource("/myfolder/testres.txt"); assertEquals(f, resource.getFile()); File resourceFile = resourceLoadingService.getResourceAsFile("/myfolder/testres.txt"); assertEquals(f, resourceFile); // file可创建 f = new File(srcdir, "/not/found"); resource = resourceLoadingService.getResource("/basedir/not/found", FOR_CREATE); assertEquals(f, resource.getFile()); resourceFile = resourceLoadingService.getResourceAsFile("/basedir/not/found", FOR_CREATE); assertEquals(f, resourceFile); // file不存在 resource = resourceLoadingService.getResource("/classpath/java/lang/String.class"); assertEquals(null, resource.getFile()); try { resourceLoadingService.getResourceAsFile("/classpath/java/lang/String.class"); fail(); } catch (ResourceNotFoundException e) { assertThat(e, exception("Could not get File of resource", "/classpath/java/lang/String.class")); } } @Test public void getResourceAsURL() throws Exception { resourceLoadingService = (ResourceLoadingService) factory.getBean("getResourceAs"); // URL存在 URL u = new File(srcdir, "/myfolder/testres.txt").toURI().toURL(); Resource resource = resourceLoadingService.getResource("/myfolder/testres.txt"); assertEquals(u, resource.getURL()); URL resourceURL = resourceLoadingService.getResourceAsURL("/myfolder/testres.txt"); assertEquals(u, resourceURL); // URL不存在 resource = resourceLoadingService.getResource("/asURL/java/lang/String.class"); assertEquals(null, resource.getURL()); try { resourceLoadingService.getResourceAsURL("/asURL/java/lang/String.class"); fail(); } catch (ResourceNotFoundException e) { assertThat(e, exception("Could not get URL of resource", "/asURL/java/lang/String.class")); } } @Test public void getResourceAsStream() throws Exception { resourceLoadingService = (ResourceLoadingService) factory.getBean("getResourceAs"); String testresContent = readText(new FileInputStream(new File(srcdir, "/myfolder/testres.txt")), null, true); // Stream存在 Resource resource = resourceLoadingService.getResource("/myfolder/testres.txt"); assertEquals(testresContent, readText(resource.getInputStream(), null, true)); assertEquals(testresContent, readText(resourceLoadingService.getResourceAsStream("/myfolder/testres.txt"), null, true)); // Stream不存在 resource = resourceLoadingService.getResource("/asStream/java/lang/String.class"); assertEquals(null, resource.getInputStream()); try { resourceLoadingService.getResourceAsStream("/asStream/java/lang/String.class"); fail(); } catch (ResourceNotFoundException e) { assertThat(e, exception("Could not get InputStream of resource", "/asStream/java/lang/String.class")); } } @Test public void exists() throws Exception { resourceLoadingService = (ResourceLoadingService) factory.getBean("getResourceAs"); assertTrue(resourceLoadingService.exists("/myfolder/testres.txt")); assertTrue(resourceLoadingService.exists("/classpath/java/lang/String.class")); assertTrue(resourceLoadingService.exists("/asURL/java/lang/String.class")); assertTrue(resourceLoadingService.exists("/asStream/java/lang/String.class")); assertFalse(resourceLoadingService.exists("/not/found")); } @Test public void getPatterns_noParent() { assertArrayEquals(new String[] {// "/my/alias1", // "/my/alias2", // "/my/alias3", // "/my/alias4", // "/my/alias5", // "/my/alias6", // "/my/alias7", // "/my/resource", // "relative/resource", // "/absolute/resource", // }, resourceLoadingService.getPatterns(false)); } @Test public void getPatterns_withParent() { assertArrayEquals(new String[] {// "/my/alias1", // "/my/alias2", // "/my/alias3", // "/my/alias4", // "/my/alias5", // "/my/alias6", // "/my/alias7", // "/my/resource", // "relative/resource", // "/absolute/resource", // "/classpath", // parent "/", // parent }, resourceLoadingService.getPatterns(true)); } /** * 当存在多个loaders,第一个loader找到的resource不存在(option=FOR_CREATE), * 第二个loader找到的resource已经存在,则返回第二个。 */ @Test public void getResource_priority() { resourceLoadingService = (ResourceLoadingService) factory.getBean("resourcePriority"); // 1. config/web.xml - not exists // 2. config/folder/web.xml - not exists // 3. config/WEB-INF/web.xml - exists // returns 3 Resource resource = resourceLoadingService.getResource("/resourcePriority/web.xml", FOR_CREATE); assertTrue(resource.exists()); assertEquals(new File(srcdir, "WEB-INF/web.xml"), resource.getFile()); // 1. config/web2.xml - not exists // 2. config/folder/web2.xml - not exists // 3. config/WEB-INF/web2.xml - not exists // returns 1 resource = resourceLoadingService.getResource("/resourcePriority/web2.xml", FOR_CREATE); assertFalse(resource.exists()); assertEquals(new File(srcdir, "web2.xml"), resource.getFile()); } private void assertResourceNotFoundException(Throwable e, String... messages) { for (String msg : messages) { assertThat(e, exception(ResourceNotFoundException.class, msg)); e = e.getCause(); } assertThat(e, nullValue()); } /** 除去resource URL的filter。 */ public static class NoURLFilter implements ResourceFilter { public void init(ResourceLoadingService resourceLoadingService) { } public Resource doFilter(ResourceMatchResult filterMatchResult, Set<ResourceLoadingOption> options, ResourceFilterChain chain) throws ResourceNotFoundException { Resource resource = chain.doFilter(filterMatchResult, options); try { return new InputStreamResource(resource.getInputStream()); } catch (IOException e) { fail(); return null; } } } /** 除去resource Stream的filter。 */ public static class NoStreamFilter implements ResourceFilter { public void init(ResourceLoadingService resourceLoadingService) { } public Resource doFilter(ResourceMatchResult filterMatchResult, Set<ResourceLoadingOption> options, ResourceFilterChain chain) throws ResourceNotFoundException { final Resource resource = chain.doFilter(filterMatchResult, options); return new Resource() { public boolean exists() { return resource.exists(); } public File getFile() { return resource.getFile(); } public InputStream getInputStream() throws IOException { return null; } public URL getURL() { return resource.getURL(); } public long lastModified() { return resource.lastModified(); } }; } } }