| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.naming.resources; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Hashtable; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| |
| import javax.naming.NamingException; |
| import javax.naming.directory.Attributes; |
| |
| import org.apache.naming.NamingEntry; |
| |
| /** |
| * Extended FileDirContext implementation that will allow loading of tld files |
| * from the META-INF directory (or subdirectories) in classpath. This will fully |
| * mimic the behavior of compressed jars also when using unjarred resources. Tld |
| * files can be loaded indifferently from WEB-INF webapp dir (or subdirs) or |
| * from META-INF dir from jars available in the classpath: using this DirContext |
| * implementation you will be able to use unexpanded jars during development and |
| * to make any tld in them virtually available to the webapp. |
| * |
| * Sample context xml configuration: |
| * |
| * <code> |
| * <Context docBase="\webapps\mydocbase"> |
| * <Resources className="org.apache.naming.resources.VirtualDirContext" |
| * virtualClasspath="\dir\classes;\somedir\somejar.jar"/> |
| * </Resources> |
| * </code> |
| * |
| * |
| * <strong>This is not meant to be used for production. |
| * Its meant to ease development with IDE's without the |
| * need for fully republishing jars in WEB-INF/lib</strong> |
| * |
| * |
| * @author Fabrizio Giustina |
| * @version $Id: VirtualDirContext.java,v 1.1 2011/06/28 21:14:09 rherrmann Exp $ |
| */ |
| public class VirtualDirContext extends FileDirContext { |
| |
| /** |
| * Map containing generated virtual names for tld files under WEB-INF and |
| * the actual file reference. |
| */ |
| private Map<String, File> virtualMappings; |
| |
| /** |
| * Map containing a mapping for tag files that should be loaded from the |
| * META-INF dir of referenced jar files. |
| */ |
| private Map<String, File> tagfileMappings; |
| |
| /** |
| * <code>;</code> separated list of virtual path elements. |
| */ |
| private String virtualClasspath; |
| |
| /** |
| * <code>virtualClasspath</code> attribute that will be automatically set |
| * from the <code>Context</code> <code>virtualClasspath</code> attribute |
| * from the context xml file. |
| * @param path <code>;</code> separated list of path elements. |
| */ |
| public void setVirtualClasspath(String path) { |
| virtualClasspath = path; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void allocate() { |
| super.allocate(); |
| |
| virtualMappings = new Hashtable<String, File>(); |
| tagfileMappings = new Hashtable<String, File>(); |
| |
| // looks into any META-INF dir found in classpath entries for tld files. |
| StringTokenizer tkn = new StringTokenizer(virtualClasspath, ";"); |
| while (tkn.hasMoreTokens()) { |
| File file = new File(tkn.nextToken(), "META-INF"); |
| |
| if (!file.exists() || !file.isDirectory()) { |
| continue; |
| } |
| scanForTlds(file); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void release() { |
| super.release(); |
| virtualMappings = null; |
| } |
| |
| @Override |
| public Attributes getAttributes(String name) throws NamingException { |
| |
| // handle "virtual" tlds |
| if (name.startsWith("/WEB-INF/") && name.endsWith(".tld")) { |
| String tldName = name.substring(name.lastIndexOf("/") + 1); |
| if (virtualMappings.containsKey(tldName)) { |
| return new FileResourceAttributes(virtualMappings.get(tldName)); |
| } |
| } else if (name.startsWith("/META-INF/tags") && name.endsWith(".tag") |
| || name.endsWith(".tagx")) { |
| |
| // already loaded tag file |
| if (tagfileMappings.containsKey(name)) { |
| return new FileResourceAttributes(tagfileMappings.get(name)); |
| } |
| |
| // unknown tagfile, search for it in virtualClasspath |
| StringTokenizer tkn = new StringTokenizer(virtualClasspath, ";"); |
| while (tkn.hasMoreTokens()) { |
| File file = new File(tkn.nextToken(), name); |
| if (file.exists()) { |
| tagfileMappings.put(name, file); |
| return new FileResourceAttributes(file); |
| } |
| } |
| } |
| |
| return super.getAttributes(name); |
| } |
| |
| @Override |
| protected List<NamingEntry> list(File file) { |
| List<NamingEntry> entries = super.list(file); |
| |
| // adds virtual tlds for WEB-INF listing |
| if ("WEB-INF".equals(file.getName())) { |
| entries.addAll(getVirtualNamingEntries()); |
| } |
| |
| return entries; |
| } |
| |
| @Override |
| protected Object doLookup(String name) { |
| |
| // handle "virtual" tlds |
| if (name.startsWith("/WEB-INF/") && name.endsWith(".tld")) { |
| String tldName = name.substring(name.lastIndexOf("/") + 1); |
| if (virtualMappings.containsKey(tldName)) { |
| return new FileResource(virtualMappings.get(tldName)); |
| } |
| } else if (name.startsWith("/META-INF/tags") && name.endsWith(".tag") |
| || name.endsWith(".tagx")) { |
| |
| // already loaded tag file: we are sure that getAttributes() has |
| // already been called if we are here |
| File tagFile = tagfileMappings.get(name); |
| if (tagFile != null) { |
| return new FileResource(tagFile); |
| } |
| } |
| |
| return super.doLookup(name); |
| } |
| |
| /** |
| * Scan a given dir for tld files. Any found tld will be added to the |
| * virtualMappings. |
| * @param dir Dir to scan for tlds |
| */ |
| private void scanForTlds(File dir) { |
| |
| File[] files = dir.listFiles(); |
| for (int j = 0; j < files.length; j++) { |
| File file = files[j]; |
| |
| if (file.isDirectory()) { |
| scanForTlds(file); |
| } else if (file.getName().endsWith(".tld")) { |
| // just generate a random name using the current timestamp, name |
| // doesn't matter since it needs to be referenced by URI |
| String virtualTldName = "~" + System.currentTimeMillis() + "~" |
| + file.getName(); |
| virtualMappings.put(virtualTldName, file); |
| } |
| } |
| |
| } |
| |
| /** |
| * Returns a list of virtual naming entries. |
| * @return list of naming entries, containing tlds in virtualMappings |
| */ |
| private List<NamingEntry> getVirtualNamingEntries() { |
| List<NamingEntry> virtual = new ArrayList<NamingEntry>(); |
| |
| for (String name : virtualMappings.keySet()) { |
| |
| File file = virtualMappings.get(name); |
| NamingEntry entry = new NamingEntry(name, new FileResource(file), |
| NamingEntry.ENTRY); |
| virtual.add(entry); |
| } |
| return virtual; |
| } |
| |
| } |