001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021
022package org.biojava.utils.xml;
023
024import java.io.IOException;
025import java.io.InputStream;
026import java.util.ArrayList;
027import java.util.List;
028import java.util.StringTokenizer;
029
030import org.biojava.utils.ClassTools;
031import org.xml.sax.EntityResolver;
032import org.xml.sax.InputSource;
033import org.xml.sax.SAXException;
034
035/**
036 * SAX EntityResolve which looks up system IDs as resources
037 * from a Java ClassLoader.
038 *
039 * @author Thomas Down
040 * @since 1.2
041 */
042
043public class ResourceEntityResolver implements EntityResolver {
044    private String[] path;
045    private ClassLoader classLoader;
046
047    private String[] parsePath(String path) {
048        List pathElements = new ArrayList();
049        StringTokenizer toke = new StringTokenizer(path, ":");
050        while (toke.hasMoreTokens()) {
051            pathElements.add(toke.nextToken());
052        }
053        
054        return (String[]) pathElements.toArray(new String[0]);
055    }
056
057    /**
058     * Construct a resolver which searches for resources in the specified
059     * path relative to the current classloader.
060     */
061
062    public ResourceEntityResolver(String path) {
063        super();
064        this.path = parsePath(path);
065        this.classLoader = ClassTools.getClassLoader(this);
066    }
067    
068    /**
069     * Construct a resolver which searches for resources in the specified
070     * list of directories relative to the current classloader.
071     */
072
073    public ResourceEntityResolver(String[] path) {
074        super();
075        this.path = path;
076        this.classLoader = ClassTools.getClassLoader(this);
077    }
078
079    /**
080     * Construct a resolver which searches for resources in the specified
081     * list of directories relative to the supplied classloader.
082     */
083
084    public ResourceEntityResolver(String[] path, ClassLoader classLoader) {
085        this.path = path;
086        this.classLoader = classLoader;
087    }
088
089    /**
090     * Construct a resolver which searches for resources in the specified
091     * path relative to the supplied classloader.
092     */
093
094    public ResourceEntityResolver(String path, ClassLoader classLoader) {
095        this.path = parsePath(path);
096        this.classLoader = classLoader;
097    }
098
099    public InputSource resolveEntity(String publicId,
100                                     String systemId)
101        throws SAXException, IOException
102    {
103        int index = systemId.lastIndexOf('/');
104        if (index >= 0) {
105            systemId = systemId.substring(index + 1);
106        }
107
108        for (int i = 0; i < path.length; ++i) {
109            InputStream is = classLoader.getResourceAsStream(path[i] + "/" + systemId);
110            if (is != null) {
111                InputSource source = new InputSource(is);
112                source.setPublicId(publicId);
113                source.setSystemId(systemId);
114                return source;
115            }
116        }
117
118        return null;
119    }
120}
121