Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ldeck/1156957 to your computer and use it in GitHub Desktop.
Save ldeck/1156957 to your computer and use it in GitHub Desktop.
Experimental ResourceRequestHandler implementation to handle resources inside JARs.
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import com.webobjects.appserver.WOApplication;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WORequestHandler;
import com.webobjects.appserver.WOResourceManager;
import com.webobjects.appserver.WOResponse;
import com.webobjects.appserver._private.WOResourceRequestHandler;
import com.webobjects.appserver._private.WOShared;
import com.webobjects.appserver._private.WOURLValuedElementData;
import com.webobjects.foundation.NSBundle;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSLog;
import com.webobjects.foundation.NSNotificationCenter;
import com.webobjects.foundation.NSPathUtilities;
import er.extensions.foundation.ERXDictionaryUtilities;
import er.extensions.foundation.ERXProperties;
/**
* @author <a href="mailto:hprange@gmail.com.br">Henrique Prange</a>
*/
public class JarResourceRequestHandler extends WOResourceRequestHandler {
private static final Logger LOGGER = Logger.getLogger(JarResourceRequestHandler.class);
private final WOApplication _app;
private String _documentRoot;
public JarResourceRequestHandler() {
_app = WOApplication.application();
_documentRoot = null;
}
@SuppressWarnings("all")
protected WOResponse _generateResponseForInputStream(InputStream is, long length, String type) {
WOResponse response = _app.createResponseInContext(null);
if (is != null) {
if (length != 0) {
response.setContentStream(is, 50 * 1024, length);
}
} else {
response.setStatus(404);
}
if (type != null) {
response.setHeader(type, "content-type");
}
if (length != 0) {
response.setHeader("" + length, "content-length");
}
return response;
}
private String documentRoot() {
if (_documentRoot == null) {
_documentRoot = ERXProperties.stringForKey("WODocumentRoot");
if (_documentRoot == null) {
NSBundle bundle = NSBundle.bundleForName("JavaWebObjects");
NSDictionary dict = ERXDictionaryUtilities.dictionaryFromPropertyList("WebServerConfig", bundle);
_documentRoot = (String) dict.objectForKey("DocumentRoot");
}
}
return _documentRoot;
}
protected WOResponse generateResponseForInputStream(InputStream is, long aContentLength, String aContentType) {
WOResponse aResponse = _app.createResponseInContext(null);
if (aContentType != null) {
aResponse.setHeader(aContentType, "content-type");
}
if (is != null && aContentLength != 0L) {
aResponse.setHeader(Long.toString(aContentLength), "content-length");
aResponse.setContentStream(is, 131072, aContentLength);
} else {
LOGGER.warn("The resource was not found. Turn log DEBUG on for more details.");
aResponse.setStatus(404);
aResponse.setHeader(WOShared.unsignedIntString(0), "content-length");
}
return aResponse;
}
@Override
public WOResponse handleRequest(WORequest request) {
WOResponse response = null;
FileInputStream is = null;
int length = 0;
String contentType = null;
String uri = request.uri();
if (uri.charAt(0) == '/') {
WOResourceManager rm = _app.resourceManager();
String documentRoot = documentRoot();
File file = null;
StringBuffer sb = new StringBuffer(documentRoot.length() + uri.length());
String wodataKey = request.stringFormValueForKey("wodata");
if (uri.startsWith("/cgi-bin") && wodataKey != null) {
uri = wodataKey;
if (uri.startsWith("file:")) {
// remove file:/
uri = uri.substring(5);
}
} else {
int index = uri.indexOf("/wodata=");
if (index >= 0) {
uri = uri.substring(index + "/wodata=".length());
} else {
sb.append(documentRoot);
}
}
sb.append(uri);
String path = sb.toString();
try {
path = path.replace('+', ' ');
path = path.replaceAll("\\?.*", "");
file = new File(path);
length = (int) file.length();
is = new FileInputStream(file);
contentType = rm.contentTypeForResourceNamed(path);
LOGGER.debug("Reading file '" + file + "' for uri: " + uri);
} catch (IOException ex) {
if (!uri.toLowerCase().endsWith("/favicon.ico")) {
LOGGER.debug("Unable to get contents of file '" + file + "' for uri: " + uri);
return handleRequestWithResourceInsideJar(request);
}
}
} else {
LOGGER.error("Can't fetch relative path: " + uri);
}
response = _generateResponseForInputStream(is, length, contentType);
NSNotificationCenter.defaultCenter().postNotification(WORequestHandler.DidHandleRequestNotification, response);
response._finalizeInContext(null);
return response;
}
public WOResponse handleRequestWithResourceInsideJar(WORequest request) {
LOGGER.debug("Handling the request for (entire URI) " + request.uri());
boolean requestHandlerContainsPath = false;
String requestHandlerPath = request.requestHandlerPath();
String resourceDataKey = request.stringFormValueForKey("wodata");
if (requestHandlerPath != null
&& (requestHandlerPath.endsWith(".class") || requestHandlerPath.endsWith(".jar") || requestHandlerPath.endsWith(".zip") || requestHandlerPath
.endsWith(".table")) && requestHandlerPath.indexOf("..") == requestHandlerPath.indexOf('~')) {
requestHandlerContainsPath = true;
}
WOResponse response = null;
if (requestHandlerContainsPath && _app.isDirectConnectEnabled()) {
LOGGER.debug("The path to resources is (based on request handler path) " + requestHandlerPath);
response = responseForJavaClassAtPath(requestHandlerPath);
} else if (StringUtils.isNotBlank(requestHandlerPath) && resourceDataKey == null) {
// A classe ERXResourceManager altera a URL de forma errada. Ao
// invés de ?wodata=, o Anjo mudou para /wodata=. Isso faz com
// que seja necessário tratarmos aqui essa key.
requestHandlerPath = StringUtils.replace(requestHandlerPath, "wodata=", "");
// Tosca modificacao para carregar recursos no WO541 e Wonder 4 em Windows
requestHandlerPath = StringUtils.replace(requestHandlerPath, "%3A", ":");
LOGGER.debug("The path to resources is (based on a corrected path) " + requestHandlerPath);
URL resourcesUrl = null;
try {
resourcesUrl = new URL("file", "", requestHandlerPath);
response = responseForDataAtURL(resourcesUrl);
} catch (MalformedURLException exception) {
LOGGER.error("An error occurred while trying to handle the resource", exception);
}
} else if (resourceDataKey != null) {
LOGGER.debug("The path to resources is (based on wodata key) " + resourceDataKey);
response = responseForDataCachedWithKey(resourceDataKey);
}
if (response == null) {
LOGGER.warn("THE REQUEST CANNOT BE CORRECTLY HANDLED. GENERATING AN EMPTY RESPONSE.");
String contentType = request.headerForKey("content-type");
if (contentType == null) {
contentType = "text/plain";
}
response = generateResponseForInputStream(null, 0L, contentType);
}
NSNotificationCenter.defaultCenter().postNotification(WORequestHandler.DidHandleRequestNotification, response);
response._finalizeInContext(null);
return response;
}
protected WOResponse responseForDataAtURL(URL anURL) {
InputStream is = null;
long fileLength = 0L;
String aResourcePath = anURL.toString();
String aContentType = _app.resourceManager().contentTypeForResourceNamed(aResourcePath);
try {
fileLength = NSPathUtilities._contentLengthForPathURL(anURL);
is = anURL.openStream();
} catch (IOException ioe) {
NSLog.err.appendln((new StringBuilder()).append("<").append(getClass().getName()).append("> Unable to get contents of file for path '").append(
aResourcePath).append("': ").append(ioe).toString());
if (NSLog.debugLoggingAllowedForLevelAndGroups(2, 36L)) {
NSLog.debug.appendln(ioe);
}
}
WOResponse aResponse = generateResponseForInputStream(is, fileLength, aContentType);
return aResponse;
}
protected WOResponse responseForDataCachedWithKey(String aResourceKey) {
WOResponse response = _app.createResponseInContext(null);
WOResourceManager resourceManager = _app.resourceManager();
WOURLValuedElementData aResourceDataObject = resourceManager._cachedDataForKey(aResourceKey);
if (aResourceDataObject == null) {
LOGGER.warn("The resource was not found in cache. Turn log DEBUG on for more details.");
return response;
}
aResourceDataObject.appendToResponse(response, null);
if (aResourceDataObject.isTemporary()) {
resourceManager.removeDataForKey(aResourceKey, null);
}
return response;
}
protected WOResponse responseForJavaClassAtPath(String aPath) {
WOResponse aResponse = null;
URL anURL = _app.resourceManager()._pathURLForJavaClass(aPath);
if (anURL != null) {
aResponse = responseForDataAtURL(anURL);
}
return aResponse;
}
}
@ldeck
Copy link
Author

ldeck commented Aug 19, 2011

Hi Henrique, I've made a couple of minor changes that you might want to pull in. Also, this would be useful to put into Wonder (or some published jar) so we can refer to it in the archetypes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment