org.nuiton.util.ResourceResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nuiton-utils Show documentation
Show all versions of nuiton-utils Show documentation
Library of usefull classes to be used in any project.
/*
* #%L
* Nuiton Utils
* %%
* Copyright (C) 2004 - 2010 CodeLutin
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nuiton.util;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.stream.StreamSource;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
*
* ResourceResolver is a URIResolver for XSL transformation.
*
*
* Its purpose is to catch the XSL document(...) function call and return a
* valid data source only if the wanted resource is present in the project
* resources.
*
* The main goal of ResourceResolver is to retrieve datasources locally, if the
* wanted resource is not present in project resource then null will be
* returned.
*
* The resolve function search for the file part of href parameter:
*
* - href: http://argouml.org/profiles/uml14/default-uml14.xmi
* - file part: default-uml14.xmi.
*
* The resource is searched this way:
*
* - eg: {@code [file part extension]/[file part]}
* - eg: {@code xmi/default-uml14.xmi}
*
*
* You should assign this ResourceResolver on
* {@link Transformer} but not on {@link TransformerFactory}.
*
* @author chorlet
*/
public class ResourceResolver implements URIResolver {
/** log. */
private static final Log log = LogFactory.getLog(ResourceResolver.class);
/** Shared Cache to not search in full classpath at each request. */
protected static final SortedMap sourceCache =
new TreeMap();
/** Shared Cache of not local resources */
protected static final Set unresolvedCache = new HashSet();
/** le pattern de detection d'une uri */
public static final Pattern HREF_PATTERN =
Pattern.compile("([a-zA-Z]+)\\:\\/\\/(.+)");
/** Pour vider le cache partage. */
public static synchronized void clearCache() {
sourceCache.clear();
unresolvedCache.clear();
}
protected String base;
/** le niveau de verbosite */
protected boolean verbose = log.isDebugEnabled();
/** le classe loader utilise pour recuperer les resources */
protected ClassLoader cl = getClass().getClassLoader();
public ResourceResolver() {
this(null);
}
public ResourceResolver(String base) {
if (base != null && base.endsWith("/") && base.length() > 1) {
base = base.substring(0, base.length() - 1);
}
this.base = base;
if (log.isTraceEnabled()) {
log.trace(this + ", base : " + this.base);
}
}
/**
* Resolve href on local resource.
*
* @return null if local resource not found
*/
@Override
public synchronized Source resolve(String href, String base) {
if (unresolvedCache.contains(href)) {
// href was already unfound in class-path,
// do not search twice (class-path search can be expensive)
if (verbose) {
log.info("Skip unresolved " + href);
}
return null;
}
if (sourceCache.containsKey(href)) {
// directly use the cached source, skip all other stuff
if (verbose) {
log.info("use cached source " + href);
}
return sourceCache.get(href);
}
// at this point, the href is undiscovered, try to find in in class-path
if (verbose) {
log.info("Resolving " + href);
}
// URI :
// example 1 : pathmap://UML_METAMODELS/UML.metamodel.uml
// example 2 : http://argouml.org/profiles/uml14/default-java.xmi
// relative path :
// example 3 : xxx/zzz/ttt.uml
Source source;
// if URI
Matcher matcher = HREF_PATTERN.matcher(href);
if (matcher.matches()) {
// String protocol = matcher.group(1);
String path = matcher.group(2);
// try look only with the filename
// this is the last chance to find something :)
source = findHrefSource(path);
} else {
// no protocol, so should be a relative path location
source = findRelativeSource(href);
}
if (source == null) {
// means this resolver was not able to find the source
if (verbose) {
log.info("detect unresolved source " + href);
}
unresolvedCache.add(href);
} else {
// find a new cacheable source, add it in cache
if (verbose) {
log.info("detect cacheable source " + href);
}
sourceCache.put(href, source);
}
// if (href.matches("[a-zA-Z]+://.+")) {
// String filename = null;
// int beginIndex = href.lastIndexOf('/');
// if (beginIndex > -1) {
// filename = href.substring(beginIndex + 1);
// }
// if (filename != null && !filename.isEmpty()) {
// source = findSource(filename, true);
// }
// } else {
// source = findSource(href, false);
// }
return source;
}
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
public void setCl(ClassLoader cl) {
this.cl = cl;
}
protected Source findHrefSource(String path) {
long t0 = System.nanoTime();
String filename;
int beginIndex = path.lastIndexOf('/');
if (beginIndex > -1) {
filename = path.substring(beginIndex + 1);
} else {
filename = path;
}
if (filename == null || filename.isEmpty()) {
return null;
}
String resource;
resource = ".*/" + filename;
if (verbose) {
log.info("will discover " + resource);
}
URL url = null;
// use given classloader to work in maven
List urls = null;
URLClassLoader ucl = null;
if (cl == null) {
ClassLoader cl2 = getClass().getClassLoader();
if (cl2 instanceof URLClassLoader) {
ucl = (URLClassLoader) cl2;
}
}
if (cl instanceof URLClassLoader) {
ucl = (URLClassLoader) cl;
}
try {
urls = Resource.getURLs(resource, ucl);
} catch (ResourceNotFoundException rnfe) {
// Nothing to do
}
if (urls != null && !urls.isEmpty()) {
url = urls.get(0);
}
Source source = null;
if (url != null) {
if (verbose) {
log.info(url.toString());
}
source = new StreamSource(url.toString());
}
if (verbose) {
String time = StringUtil.convertTime(System.nanoTime() - t0);
log.info("resolved in " + time);
}
return source;
}
protected Source findRelativeSource(String path) {
long t0 = System.nanoTime();
String filename = path;
// int beginIndex = path.lastIndexOf('/');
// if (beginIndex > -1) {
// filename = path.substring(beginIndex + 1);
// } else {
// filename = path;
// }
// if (filename == null || filename.isEmpty()) {
// return null;
// }
String resource;
if (base != null) {
resource = base + "/" + filename;
} else {
resource = filename;
}
if (verbose) {
log.info("will discover " + resource);
}
URL url = Resource.getURLOrNull(resource);
Source source = null;
if (url != null) {
if (verbose) {
log.info(url.toString());
}
source = new StreamSource(url.toString());
}
if (verbose) {
String time = StringUtil.convertTime(System.nanoTime() - t0);
log.info("resolved in " + time);
}
return source;
}
}