org.apache.naming.resources.VirtualDirContext Maven / Gradle / Ivy
/*
* 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.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import org.apache.naming.NamingEntry;
/**
* Extended FileDirContext implementation that allows to expose multiple
* directories of the filesystem under a single webapp, a feature mainly used
* for development with IDEs.
* This should be used in conjunction with
* {@link org.apache.catalina.loader.VirtualWebappLoader}.
*
* Sample context xml configuration:
*
*
* <Context path="/mywebapp" docBase="/Users/theuser/mywebapp/src/main/webapp" >
* <Resources className="org.apache.naming.resources.VirtualDirContext"
* extraResourcePaths="/pictures=/Users/theuser/mypictures,/movies=/Users/theuser/mymovies" />
* <Loader className="org.apache.catalina.loader.VirtualWebappLoader"
* virtualClasspath="/Users/theuser/mywebapp/target/classes" />
* <JarScanner scanAllDirectories="true" />
* </Context>
*
*
*
* 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
*
*
* @author Fabrizio Giustina
* @version $Id: VirtualDirContext.java 1371816 2012-08-10 19:54:55Z markt $
*/
public class VirtualDirContext extends FileDirContext {
private String extraResourcePaths = "";
private Map> mappedResourcePaths;
/**
*
* Allows to map a path of the filesystem to a path in the webapp. Multiple
* filesystem paths can be mapped to the same path in the webapp. Filesystem
* path and virtual path must be separated by an equal sign. Pairs of paths
* must be separated by a comma.
*
* Example:
* /=/Users/slaurent/mywebapp/src/main/webapp;/pictures=/Users/slaurent/sharedpictures
*
*
* The path to the docBase must not be added here, otherwise resources would
* be listed twice.
*
*
* @param path
*/
public void setExtraResourcePaths(String path) {
extraResourcePaths = path;
}
/**
* {@inheritDoc}
*/
@Override
public void allocate() {
super.allocate();
mappedResourcePaths = new HashMap>();
StringTokenizer tkn = new StringTokenizer(extraResourcePaths, ",");
while (tkn.hasMoreTokens()) {
String resSpec = tkn.nextToken();
if (resSpec.length() > 0) {
int idx = resSpec.indexOf('=');
String path;
if (idx <= 0) {
path = "";
}
else {
if (resSpec.startsWith("/=")) {
resSpec = resSpec.substring(1);
idx--;
}
path = resSpec.substring(0, idx);
}
String dir = resSpec.substring(idx + 1);
List resourcePaths = mappedResourcePaths.get(path);
if (resourcePaths == null) {
resourcePaths = new ArrayList();
mappedResourcePaths.put(path, resourcePaths);
}
resourcePaths.add(dir);
}
}
if (mappedResourcePaths.isEmpty()) {
mappedResourcePaths = null;
}
}
/**
* {@inheritDoc}
*/
@Override
public void release() {
mappedResourcePaths = null;
super.release();
}
@Override
public Attributes getAttributes(String name) throws NamingException {
NamingException initialException;
try {
// first try the normal processing, if it fails try with extra
// resources
Attributes attributes = super.getAttributes(name);
return attributes;
} catch (NamingException exc) {
initialException = exc;
}
if (mappedResourcePaths != null) {
for (Map.Entry> mapping : mappedResourcePaths.entrySet()) {
String path = mapping.getKey();
List dirList = mapping.getValue();
String resourcesDir = dirList.get(0);
if (name.equals(path)) {
File f = new File(resourcesDir);
if (f.exists() && f.canRead()) {
return new FileResourceAttributes(f);
}
}
path += "/";
if (name.startsWith(path)) {
String res = name.substring(path.length());
File f = new File(resourcesDir + "/" + res);
if (f.exists() && f.canRead()) {
return new FileResourceAttributes(f);
}
}
}
}
throw initialException;
}
@Override
protected File file(String name) {
File file = super.file(name);
if (file != null || mappedResourcePaths == null) {
return file;
}
// If not found under docBase, try our other resources
// Ensure name string begins with a slash
if (name.length() > 0 && name.charAt(0) != '/') {
name = "/" + name;
}
for (Map.Entry> mapping : mappedResourcePaths.entrySet()) {
String path = mapping.getKey();
List dirList = mapping.getValue();
if (name.equals(path)) {
for (String resourcesDir : dirList) {
file = new File(resourcesDir);
if (file.exists() && file.canRead()) {
return file;
}
}
}
if (name.startsWith(path + "/")) {
String res = name.substring(path.length());
for (String resourcesDir : dirList) {
file = new File(resourcesDir, res);
if (file.exists() && file.canRead()) {
return file;
}
}
}
}
return null;
}
@Override
protected List list(File file) {
List entries = super.list(file);
if (mappedResourcePaths != null && !mappedResourcePaths.isEmpty()) {
Set entryNames = new HashSet(entries.size());
for (NamingEntry entry : entries) {
entryNames.add(entry.name);
}
// Add appropriate entries from the extra resource paths
String absPath = file.getAbsolutePath();
if (absPath.startsWith(getDocBase() + File.separator)) {
String relPath = absPath.substring(getDocBase().length());
String fsRelPath = relPath.replace(File.separatorChar, '/');
for (Map.Entry> mapping : mappedResourcePaths.entrySet()) {
String path = mapping.getKey();
List dirList = mapping.getValue();
String res = null;
if (fsRelPath.equals(path)) {
res = "";
} else if (fsRelPath.startsWith(path + "/")) {
res = relPath.substring(path.length());
}
if (res != null) {
for (String resourcesDir : dirList) {
File f = new File(resourcesDir, res);
if (f.exists() && f.canRead() && f.isDirectory()) {
List virtEntries = super.list(f);
for (NamingEntry entry : virtEntries) {
// filter duplicate
if (!entryNames.contains(entry.name)) {
entryNames.add(entry.name);
entries.add(entry);
}
}
}
}
}
}
}
}
return entries;
}
@Override
protected Object doLookup(String name) {
Object retSuper = super.doLookup(name);
if (retSuper != null || mappedResourcePaths == null) {
return retSuper;
}
// Perform lookup using the extra resource paths
for (Map.Entry> mapping : mappedResourcePaths.entrySet()) {
String path = mapping.getKey();
List dirList = mapping.getValue();
if (name.equals(path)) {
for (String resourcesDir : dirList) {
File f = new File(resourcesDir);
if (f.exists() && f.canRead()) {
if (f.isFile()) {
return new FileResource(f);
}
else {
// never goes here, if f is a directory the super
// implementation already returned a value
}
}
}
}
path += "/";
if (name.startsWith(path)) {
String res = name.substring(path.length());
for (String resourcesDir : dirList) {
File f = new File(resourcesDir + "/" + res);
if (f.exists() && f.canRead()) {
if (f.isFile()) {
return new FileResource(f);
}
else {
// never goes here, if f is a directory the super
// implementation already returned a value
}
}
}
}
}
return retSuper;
}
@Override
protected String doGetRealPath(String path) {
File file = file(path);
if (null != file) {
return file.getAbsolutePath();
} else {
return null;
}
}
}