blob: 7de7c2d1607d5a87ac1d1e2f9935dbd37edfb426 [file] [log] [blame]
/*
* 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>
* &lt;Context docBase="\webapps\mydocbase">
* &lt;Resources className="org.apache.naming.resources.VirtualDirContext"
* virtualClasspath="\dir\classes;\somedir\somejar.jar"/>
* &lt;/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;
}
}