/** * Copyright (C) 2010 Orbeon, Inc. * * 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.1 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. * * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html */ package org.orbeon.oxf.resources; import org.apache.log4j.Logger; import org.orbeon.oxf.common.OXFException; import org.orbeon.oxf.util.LoggerFactory; import org.orbeon.oxf.util.NetUtils; import java.io.*; import java.net.*; import java.util.jar.JarEntry; /** * The classloader resource manager is able to load resources from a JAR file, * or from a directory in the system classpath. It is useful when resources are * bundled with an application. */ public class ClassLoaderResourceManagerImpl extends ResourceManagerBase { private static Logger logger = LoggerFactory.createLogger(ClassLoaderResourceManagerImpl.class); private final Class clazz; private final boolean prependSlash; private URLConnection getConnection(final String key, boolean doNotThrowResourceNotFound) throws IOException { final String adjustedKey = prependSlash && !key.startsWith("/") ? "/" + key : key; final URL u = clazz.getResource(adjustedKey); if (u == null) { if (doNotThrowResourceNotFound) return null; else throw new ResourceNotFoundException(key); } return u.openConnection(); } /** * Initialize this resource manager. */ public ClassLoaderResourceManagerImpl(final java.util.Map props) { this(props, null); } /** * Initialize this resource manager with rooted in the specified class * * @param c a root class */ public ClassLoaderResourceManagerImpl(final java.util.Map props, final Class c) { super(props); clazz = c == null ? getClass() : c; prependSlash = c == null; } /** * Returns a binary input stream for the specified key. The key could point * to any document type (text or binary). * * @param key A Resource Manager key * @return a input stream */ public InputStream getContentAsStream(String key) { if (logger.isDebugEnabled()) logger.debug("getContentAsStream(" + key + ")"); final InputStream ret; try { final URLConnection uc = getConnection(key, false); uc.setUseCaches(false); ret = uc.getInputStream(); } catch (final IOException e) { throw new OXFException(e); } return ret; } /** * Gets the last modified timestamp for the specified resource * * @param key A Resource Manager key * @param doNotThrowResourceNotFound * @return a timestamp */ protected long lastModifiedImpl(final String key, boolean doNotThrowResourceNotFound) { // NOTE: Slower implementations in the VCS history (back to 2004!). // Old impl was generating 303K of garbage per request to / in the examples app. final long ret; try { final URLConnection uc = getConnection(key, doNotThrowResourceNotFound); if (uc == null) { ret = -1; } else { if (uc instanceof JarURLConnection) { final JarEntry je = ((JarURLConnection) uc).getJarEntry(); ret = je.getTime(); } else { final URL url = uc.getURL(); final String prot = url.getProtocol(); if ("file".equalsIgnoreCase(prot)) { final String fnam = url.getPath(); final File f = new File(fnam); if (f.exists()) { ret = f.lastModified(); } else { final String fnamDec = URLDecoder.decode(fnam, "utf-8"); final File fdec = new File(fnamDec); ret = fdec.lastModified(); } } else { final long l = NetUtils.getLastModified(uc); ret = l == 0 ? 1 : l; } } } } catch (final IOException e) { throw new OXFException(e); } return ret; } /** * Returns the length of the file denoted by this abstract pathname. * * @return The length, in bytes, of the file denoted by this abstract pathname, or 0L if the file does not exist */ public int length(String key) { try { return getConnection(key, false).getContentLength(); } catch (IOException e) { throw new OXFException(e); } } /** * Indicates if the resource manager implementation suports write operations * * @return true if write operations are allowed */ public boolean canWrite(String key) { return false; } /** * Allows writing to the resource * * @param key A Resource Manager key * @return an output stream */ public OutputStream getOutputStream(String key) { throw new OXFException("Write Operation not supported"); } /** * Allow writing to the resource * * @param key A Resource Manager key * @return a writer */ public Writer getWriter(String key) { throw new OXFException("Write Operation not supported"); } public String getRealPath(String key) { return null; } }