001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.naming.resources;
018:
019: import java.io.File;
020: import java.util.ArrayList;
021: import java.util.Hashtable;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.StringTokenizer;
025:
026: import javax.naming.NamingException;
027: import javax.naming.directory.Attributes;
028:
029: import org.apache.naming.NamingEntry;
030:
031: /**
032: * Extended FileDirContext implementation that will allow loading of tld files
033: * from the META-INF directory (or subdirectories) in classpath. This will fully
034: * mimic the behavior of compressed jars also when using unjarred resources. Tld
035: * files can be loaded indifferently from WEB-INF webapp dir (or subdirs) or
036: * from META-INF dir from jars available in the classpath: using this DirContext
037: * implementation you will be able to use unexpanded jars during development and
038: * to make any tld in them virtually available to the webapp.
039: *
040: * Sample context xml configuration:
041: *
042: * <code>
043: * <Context docBase="\webapps\mydocbase">
044: * <Resources className="org.apache.naming.resources.VirtualDirContext"
045: * virtualClasspath="\dir\classes;\somedir\somejar.jar"/>
046: * </Resources>
047: * </code>
048: *
049: *
050: * <strong>This is not meant to be used for production.
051: * Its meant to ease development with IDE's without the
052: * need for fully republishing jars in WEB-INF/lib</strong>
053: *
054: *
055: * @author Fabrizio Giustina
056: * @version $Id: $
057: */
058: public class VirtualDirContext extends FileDirContext {
059:
060: /**
061: * Map containing generated virtual names for tld files under WEB-INF and
062: * the actual file reference.
063: */
064: private Map<String, File> virtualMappings;
065:
066: /**
067: * Map containing a mapping for tag files that should be loaded from the
068: * META-INF dir of referenced jar files.
069: */
070: private Map<String, File> tagfileMappings;
071:
072: /**
073: * <code>;</code> separated list of virtual path elements.
074: */
075: private String virtualClasspath;
076:
077: /**
078: * <code>virtualClasspath</code> attribute that will be automatically set
079: * from the <code>Context</code> <code>virtualClasspath</code> attribute
080: * from the context xml file.
081: * @param path <code>;</code> separated list of path elements.
082: */
083: public void setVirtualClasspath(String path) {
084: virtualClasspath = path;
085: }
086:
087: /**
088: * {@inheritDoc}
089: */
090: @Override
091: public void allocate() {
092: super .allocate();
093:
094: virtualMappings = new Hashtable<String, File>();
095: tagfileMappings = new Hashtable<String, File>();
096:
097: // looks into any META-INF dir found in classpath entries for tld files.
098: StringTokenizer tkn = new StringTokenizer(virtualClasspath, ";");
099: while (tkn.hasMoreTokens()) {
100: File file = new File(tkn.nextToken(), "META-INF");
101:
102: if (!file.exists() || !file.isDirectory()) {
103: continue;
104: }
105: scanForTlds(file);
106: }
107: }
108:
109: /**
110: * {@inheritDoc}
111: */
112: @Override
113: public void release() {
114: super .release();
115: virtualMappings = null;
116: }
117:
118: @Override
119: public Attributes getAttributes(String name) throws NamingException {
120:
121: // handle "virtual" tlds
122: if (name.startsWith("/WEB-INF/") && name.endsWith(".tld")) {
123: String tldName = name.substring(name.lastIndexOf("/") + 1);
124: if (virtualMappings.containsKey(tldName)) {
125: return new FileResourceAttributes(virtualMappings
126: .get(tldName));
127: }
128: } else if (name.startsWith("/META-INF/tags")
129: && name.endsWith(".tag") || name.endsWith(".tagx")) {
130:
131: // already loaded tag file
132: if (tagfileMappings.containsKey(name)) {
133: return new FileResourceAttributes(tagfileMappings
134: .get(name));
135: }
136:
137: // unknown tagfile, search for it in virtualClasspath
138: StringTokenizer tkn = new StringTokenizer(virtualClasspath,
139: ";");
140: while (tkn.hasMoreTokens()) {
141: File file = new File(tkn.nextToken(), name);
142: if (file.exists()) {
143: tagfileMappings.put(name, file);
144: return new FileResourceAttributes(file);
145: }
146: }
147: }
148:
149: return super .getAttributes(name);
150: }
151:
152: @Override
153: @SuppressWarnings("unchecked")
154: protected ArrayList list(File file) {
155: ArrayList entries = super .list(file);
156:
157: // adds virtual tlds for WEB-INF listing
158: if ("WEB-INF".equals(file.getName())) {
159: entries.addAll(getVirtualNamingEntries());
160: }
161:
162: return entries;
163: }
164:
165: @Override
166: public Object lookup(String name) throws NamingException {
167:
168: // handle "virtual" tlds
169: if (name.startsWith("/WEB-INF/") && name.endsWith(".tld")) {
170: String tldName = name.substring(name.lastIndexOf("/") + 1);
171: if (virtualMappings.containsKey(tldName)) {
172: return new FileResource(virtualMappings.get(tldName));
173: }
174: } else if (name.startsWith("/META-INF/tags")
175: && name.endsWith(".tag") || name.endsWith(".tagx")) {
176:
177: // already loaded tag file: we are sure that getAttributes() has
178: // already been called if we are here
179: File tagFile = tagfileMappings.get(name);
180: if (tagFile != null) {
181: return new FileResource(tagFile);
182: }
183: }
184:
185: return super .lookup(name);
186: }
187:
188: /**
189: * Scan a given dir for tld files. Any found tld will be added to the
190: * virtualMappings.
191: * @param dir Dir to scan for tlds
192: */
193: private void scanForTlds(File dir) {
194:
195: File[] files = dir.listFiles();
196: for (int j = 0; j < files.length; j++) {
197: File file = files[j];
198:
199: if (file.isDirectory()) {
200: scanForTlds(file);
201: } else if (file.getName().endsWith(".tld")) {
202: // just generate a random name using the current timestamp, name
203: // doesn't matter since it needs to be referenced by URI
204: String virtualTldName = "~"
205: + System.currentTimeMillis() + "~"
206: + file.getName();
207: virtualMappings.put(virtualTldName, file);
208: }
209: }
210:
211: }
212:
213: /**
214: * Returns a list of virtual naming entries.
215: * @return list of naming entries, containing tlds in virtualMappings
216: */
217: private List<NamingEntry> getVirtualNamingEntries() {
218: List<NamingEntry> virtual = new ArrayList<NamingEntry>();
219:
220: for (String name : virtualMappings.keySet()) {
221:
222: File file = virtualMappings.get(name);
223: NamingEntry entry = new NamingEntry(name, new FileResource(
224: file), NamingEntry.ENTRY);
225: virtual.add(entry);
226: }
227: return virtual;
228: }
229:
230: }
|