/* * eXist Open Source Native XML Database * Copyright (C) 2001-04 The eXist Project * http://exist-db.org * * 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 2 * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id$ */ package org.exist.source; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.EXistException; import org.exist.dom.persistent.BinaryDocument; import org.exist.dom.persistent.DocumentImpl; import org.exist.security.PermissionDeniedException; import org.exist.storage.BrokerPool; import org.exist.storage.DBBroker; import org.exist.storage.lock.Lock.LockMode; import org.exist.util.FileUtils; import org.exist.xmldb.XmldbURI; /** * Factory to create a {@link org.exist.source.Source} object for a given * URL. * * @author wolf */ public class SourceFactory { private final static Logger LOG = LogManager.getLogger(SourceFactory.class); /** * Create a {@link Source} object for the given URL. * <p> * As a special case, if the URL starts with "resource:", the resource * will be read from the current context class loader. * * @param broker broker, can be null if not asking for a database resource * @param contextPath * @param location * @throws MalformedURLException * @throws IOException */ public static final Source getSource(DBBroker broker, String contextPath, String location, boolean checkXQEncoding) throws IOException, PermissionDeniedException { Source source = null; /* resource: */ if (location.startsWith(ClassLoaderSource.PROTOCOL)) { source = new ClassLoaderSource(location); } else if (contextPath != null && contextPath.startsWith(ClassLoaderSource.PROTOCOL)) { // Pretend it is a file on the local system so we can resolve it easily with URL() class. final String conPathNoProtocol = contextPath.replace(ClassLoaderSource.PROTOCOL, "file://"); String resolvedURL = new URL(new URL(conPathNoProtocol), location).toString(); resolvedURL = resolvedURL.replaceFirst("file://", ClassLoaderSource.PROTOCOL); source = new ClassLoaderSource(resolvedURL); } /* file:// or location without scheme is assumed to be a file */ else if (location.startsWith("file:") || !location.contains(":")) { location = location.replaceAll("^(file:)?/*(.*)$", "$2"); try { final Path p = Paths.get(contextPath, location); if (Files.isReadable(p)) { location = p.toUri().toASCIIString(); source = new FileSource(p, checkXQEncoding); } } catch (InvalidPathException e) { // continue trying } if (source == null) { try { final Path p2 = Paths.get(location); if (Files.isReadable(p2)) { location = p2.toUri().toASCIIString(); source = new FileSource(p2, checkXQEncoding); } } catch (InvalidPathException e) { // continue trying } } if (source == null) { try { final Path p3 = Paths.get(contextPath).toAbsolutePath().resolve(location); if (Files.isReadable(p3)) { location = p3.toUri().toASCIIString(); source = new FileSource(p3, checkXQEncoding); } } catch (InvalidPathException e) { // continue trying } } if (source == null) { /* * Try to load as an absolute path */ try { final Path p4 = Paths.get("/" + location); if (Files.isReadable(p4)) { location = p4.toUri().toASCIIString(); source = new FileSource(p4, checkXQEncoding); } } catch (InvalidPathException e) { // continue trying } } if (source == null) { /* * Try to load from the folder of the contextPath */ try { final Path p5 = Paths.get(contextPath).resolveSibling(location); if (Files.isReadable(p5)) { location = p5.toUri().toASCIIString(); source = new FileSource(p5, checkXQEncoding); } } catch (InvalidPathException e) { // continue trying } } if (source == null) { /* * Try to load from the folder of the contextPath URL */ try { final Path p6 = Paths.get(contextPath.replaceFirst("^file:/*(/.*)$", "$1")).resolveSibling(location); if (Files.isReadable(p6)) { location = p6.toUri().toASCIIString(); source = new FileSource(p6, checkXQEncoding); } } catch (InvalidPathException e) { // continue trying } } if (source == null) { /* * Lastly we try to load it using EXIST_HOME as the reference point */ Path p7 = null; try { p7 = FileUtils.resolve(BrokerPool.getInstance().getConfiguration().getExistHome(), location); if (Files.isReadable(p7)) { location = p7.toUri().toASCIIString(); source = new FileSource(p7, checkXQEncoding); } } catch (final EXistException e) { LOG.warn(e); } catch (InvalidPathException e) { // continue and abort below } } if (source == null) { throw new FileNotFoundException("cannot read module source from file at " + location + ". \n"); } } /* xmldb: */ else if (location.startsWith(XmldbURI.XMLDB_URI_PREFIX)) { DocumentImpl resource = null; try { final XmldbURI pathUri = XmldbURI.create(location); resource = broker.getXMLResource(pathUri, LockMode.READ_LOCK); if (resource != null) { source = new DBSource(broker, (BinaryDocument) resource, true); } } finally { //TODO: this is nasty!!! as we are unlocking the resource whilst there //is still a source if (resource != null) { resource.getUpdateLock().release(LockMode.READ_LOCK); } } } /* resource: */ else if (location.startsWith(ClassLoaderSource.PROTOCOL)) { source = new ClassLoaderSource(location); } /* any other URL */ else { final URL url = new URL(location); source = new URLSource(url); } return source; } }