001 // Copyright 2006, 2008, 2010, 2011 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.tapestry5.ioc.internal.util; 016 017 import java.io.BufferedInputStream; 018 import java.io.IOException; 019 import java.io.InputStream; 020 import java.net.URL; 021 import java.util.Locale; 022 023 import org.apache.tapestry5.ioc.Resource; 024 import org.apache.tapestry5.ioc.util.LocalizedNameGenerator; 025 026 /** 027 * Abstract implementation of {@link Resource}. Subclasses must implement the abstract methods {@link Resource#toURL()} 028 * and {@link #newResource(String)} as well as toString(), hashCode() and equals(). 029 */ 030 public abstract class AbstractResource implements Resource 031 { 032 private final String path; 033 034 protected AbstractResource(String path) 035 { 036 assert path != null; 037 this.path = path; 038 } 039 040 public final String getPath() 041 { 042 return path; 043 } 044 045 public final String getFile() 046 { 047 int slashx = path.lastIndexOf('/'); 048 049 return path.substring(slashx + 1); 050 } 051 052 public final String getFolder() 053 { 054 int slashx = path.lastIndexOf('/'); 055 056 return (slashx < 0) ? "" : path.substring(0, slashx); 057 } 058 059 public final Resource forFile(String relativePath) 060 { 061 assert relativePath != null; 062 StringBuilder builder = new StringBuilder(getFolder()); 063 064 for (String term : relativePath.split("/")) 065 { 066 // This will occur if the relative path contains sequential slashes 067 068 if (term.equals("")) 069 continue; 070 071 if (term.equals(".")) 072 continue; 073 074 if (term.equals("..")) 075 { 076 int slashx = builder.lastIndexOf("/"); 077 078 // TODO: slashx < 0 (i.e., no slash) 079 080 // Trim path to content before the slash 081 082 builder.setLength(slashx); 083 continue; 084 } 085 086 // TODO: term blank or otherwise invalid? 087 // TODO: final term should not be "." or "..", or for that matter, the 088 // name of a folder, since a Resource should be a file within 089 // a folder. 090 091 if (builder.length() > 0) 092 builder.append("/"); 093 094 builder.append(term); 095 } 096 097 return createResource(builder.toString()); 098 } 099 100 public final Resource forLocale(Locale locale) 101 { 102 for (String path : new LocalizedNameGenerator(this.path, locale)) 103 { 104 Resource potential = createResource(path); 105 106 if (potential.exists()) 107 return potential; 108 } 109 110 return null; 111 } 112 113 public final Resource withExtension(String extension) 114 { 115 assert InternalUtils.isNonBlank(extension); 116 int dotx = path.lastIndexOf('.'); 117 118 if (dotx < 0) 119 return createResource(path + "." + extension); 120 121 return createResource(path.substring(0, dotx + 1) + extension); 122 } 123 124 /** 125 * Creates a new resource, unless the path matches the current Resource's path (in which case, this resource is 126 * returned). 127 */ 128 private Resource createResource(String path) 129 { 130 if (this.path.equals(path)) 131 return this; 132 133 return newResource(path); 134 } 135 136 /** 137 * Simple check for whether {@link #toURL()} returns null or not. 138 */ 139 public boolean exists() 140 { 141 return toURL() != null; 142 } 143 144 /** 145 * Obtains the URL for the Resource and opens the stream, wrapped by a BufferedInputStream. 146 */ 147 public InputStream openStream() throws IOException 148 { 149 URL url = toURL(); 150 151 if (url == null) 152 return null; 153 154 return new BufferedInputStream(url.openStream()); 155 } 156 157 /** 158 * Factory method provided by subclasses. 159 */ 160 protected abstract Resource newResource(String path); 161 }