/** * 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.externalcontext.WebAppContext; import java.io.*; import java.net.URL; import java.util.Map; /** * The webapp resource manager is able to load resources from a WAR file. This * is very useful when distributing packaged applications. */ public class WebAppResourceManagerImpl extends ResourceManagerBase { public static final String WEB_APP_CONTEXT_KEY = WebAppResourceManagerImpl.class.getName() + "WebAppContext"; public static final String ROOT_DIR = "oxf.resources.webapp.rootdir"; private static Logger logger = LoggerFactory.createLogger(WebAppResourceManagerImpl.class); private WebAppContext webAppContext; private String rootDirectory; public WebAppResourceManagerImpl(Map props) { super(props); WebAppContext ctx = (WebAppContext) props.get(WEB_APP_CONTEXT_KEY); if (ctx == null) throw new OXFException("WebAppResourceManager needs a WebAppContext object in its map (key=" + WEB_APP_CONTEXT_KEY + ")"); this.webAppContext = ctx; String root = (String) props.get(ROOT_DIR); if (root == null) throw new OXFException("WebAppResourceManager: property " + ROOT_DIR + " is null"); this.rootDirectory = root; } /** * 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 + ")"); InputStream result = webAppContext.getResourceAsStream(rootDirectory + key); if (result == null) throw new ResourceNotFoundException(key); return result; } /** * Gets the last modified timestamp for the specified resource * @param key A Resource Manager key * @param doNotThrowResourceNotFound * @return a timestamp */ protected long lastModifiedImpl(String key, boolean doNotThrowResourceNotFound) { try { long lm; String realPath = webAppContext.getRealPath(rootDirectory + key); if (realPath == null) { // Some application server do not return a real path, as they do // not uncompress the WAR file. This is in particular the case // when deploying compressed WAR files on Tomcat. URL url = webAppContext.getResource(rootDirectory + key); if (url == null) { if (doNotThrowResourceNotFound) return -1; else throw new ResourceNotFoundException(key); } lm = url.openConnection().getLastModified(); } else { File file = new File(realPath); if (!file.canRead()) { if (doNotThrowResourceNotFound) return -1; else throw new ResourceNotFoundException(key); } lm = file.lastModified(); } if (lm == 0) lm = 1; return lm; } catch (IOException e) { throw new OXFException(e); } } /** * Indicates if the resource manager implementation supports write operations * @return true if write operations are allowed */ public boolean canWrite(String key) { return getRealPath(key) != null; } /** * Allows writing to the resource * @param key A Resource Manager key * @return an output stream */ public OutputStream getOutputStream(String key) { final String realPath = getRealPath(key); if (realPath == null) throw new OXFException("Write Operation not supported"); try { return new FileOutputStream(realPath); } catch (FileNotFoundException e) { throw new OXFException(e); } } /** * Allow writing to the resource * @param key A Resource Manager key * @return a writer */ public Writer getWriter(String key) { final String realPath = getRealPath(key); if (realPath == null) throw new OXFException("Write Operation not supported"); try { return new FileWriter(realPath); } catch (IOException e) { throw new OXFException(e); } } /** * 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) { String realPath = webAppContext.getRealPath(rootDirectory + key); if (realPath == null) { // FIXME: this happens when the resources are in a WAR file in // WLS. In this case we should try to figure out the last modified of // the WAR itself. return 0; } else { return new Long(new File(realPath).length()).intValue(); } } public String getRealPath(String key) { return webAppContext.getRealPath(rootDirectory + key); // Need an option for this as some callers call this for non-existing files // final String realPath = servletContext.getRealPath(rootDirectory + key); // if (realPath == null) // return null; // // if (!new File(realPath).canRead()) // throw new ResourceNotFoundException("Cannot read from file " + key); // else // return realPath; } }