package org.xins.server;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.xins.common.Utils;
import org.xins.common.collections.InvalidPropertyValueException;
import org.xins.common.collections.MissingRequiredPropertyException;
import org.xins.common.manageable.InitializationException;
import org.xins.common.text.TextUtils;
public class XSLTCallingConvention extends StandardCallingConvention {
protected static final String TEMPLATES_CACHE_PROPERTY = "templates.cache";
protected static final String TEMPLATE_PARAMETER = "_template";
protected static final String CLEAR_TEMPLATE_CACHE_PARAMETER = "_cleartemplatecache";
private final TransformerFactory _factory;
private boolean _cacheTemplates;
private String _templatesPrefix;
private String _location;
private Map _templateCache;
public XSLTCallingConvention() {
_factory = TransformerFactory.newInstance();
_templateCache = new HashMap(89);
}
protected void initImpl(Map<String, String> runtimeProperties)
throws MissingRequiredPropertyException,
InvalidPropertyValueException,
InitializationException {
String cacheEnabled = runtimeProperties.get(TEMPLATES_CACHE_PROPERTY);
initCacheEnabled(cacheEnabled);
_location = getXSLTLocation(runtimeProperties, "source");
_templatesPrefix = getXSLTLocation(runtimeProperties, "parameter.prefix");
}
private void initCacheEnabled(String cacheEnabled)
throws InvalidPropertyValueException {
if (TextUtils.isEmpty(cacheEnabled)) {
_cacheTemplates = true;
} else {
cacheEnabled = cacheEnabled.trim();
if ("true".equals(cacheEnabled)) {
_cacheTemplates = true;
} else if ("false".equals(cacheEnabled)) {
_cacheTemplates = false;
} else {
throw new InvalidPropertyValueException(TEMPLATES_CACHE_PROPERTY,
cacheEnabled, "Expected either \"true\" or \"false\".");
}
}
if (_cacheTemplates) {
Log.log_3440();
} else {
Log.log_3441();
}
}
private String getXSLTLocation(Map<String, String> runtimeProperties, String propertySuffix) {
String templatesProperty = "templates." + getAPI().getName() + ".xins-xslt." + propertySuffix;
String location = runtimeProperties.get(templatesProperty);
if (TextUtils.isEmpty(location)) {
return null;
}
if (location.indexOf("://") == -1) {
String home = System.getProperty("user.dir");
String homeURL = "";
try {
homeURL = new File(home).toURL().toString();
} catch (IOException exception) {
Utils.logIgnoredException(exception);
}
location = homeURL + location;
}
Log.log_3442(getAPI().getName(), propertySuffix, location);
return location;
}
@Override
protected FunctionRequest convertRequestImpl(HttpServletRequest httpRequest)
throws InvalidRequestException,
FunctionNotSpecifiedException {
FunctionRequest request = super.convertRequestImpl(httpRequest);
Map<String, Object> backpack = request.getBackpack();
backpack.put(CLEAR_TEMPLATE_CACHE_PARAMETER, "true".equals(httpRequest.getParameter(CLEAR_TEMPLATE_CACHE_PARAMETER)));
backpack.put(TEMPLATE_PARAMETER, httpRequest.getParameter(TEMPLATE_PARAMETER));
return request;
}
protected void convertResultImpl(FunctionResult xinsResult,
HttpServletResponse httpResponse,
Map<String, Object> backpack)
throws IOException {
if (Boolean.TRUE.equals(backpack.get(CLEAR_TEMPLATE_CACHE_PARAMETER))) {
_templateCache.clear();
PrintWriter out = httpResponse.getWriter();
out.write("Done.");
out.close();
return;
}
StringWriter xmlOutput = new StringWriter(1024);
CallResultOutputter.output(xmlOutput, xinsResult);
xmlOutput.close();
String xsltLocation = null;
String templatesSuffix = (String) backpack.get(TEMPLATE_PARAMETER);
if (_templatesPrefix != null && templatesSuffix != null) {
if (templatesSuffix.indexOf("..") != -1) {
throw new IOException("Incorrect " + TEMPLATE_PARAMETER + " parameter: " + templatesSuffix);
}
xsltLocation = _templatesPrefix + templatesSuffix;
}
if (_templatesPrefix == null && templatesSuffix != null) {
throw new IOException(TEMPLATE_PARAMETER + " parameter not allowed.");
}
if (xsltLocation == null) {
if (_location == null) {
throw new IOException("No location specified for the XSLT stylesheets.");
}
xsltLocation = _location + backpack.get(BackpackConstants.FUNCTION_NAME) + ".xslt";
}
try {
Templates templates;
if (_cacheTemplates && _templateCache.containsKey(xsltLocation)) {
templates = (Templates) _templateCache.get(xsltLocation);
} else {
Log.log_3443(xsltLocation);
templates = _factory.newTemplates(new StreamSource(xsltLocation));
if (_cacheTemplates) {
_templateCache.put(xsltLocation, templates);
}
}
Transformer xformer = templates.newTransformer();
Source source = new StreamSource(new StringReader(xmlOutput.toString()));
Writer buffer = new StringWriter(4096);
Result result = new StreamResult(buffer);
xformer.transform(source, result);
String mimeType = getContentType(templates.getOutputProperties());
if (mimeType != null) {
httpResponse.setContentType(mimeType);
}
Integer backpackStatusCode = (Integer) backpack.get(BackpackConstants.STATUS_CODE);
if (backpackStatusCode == null) {
httpResponse.setStatus(HttpServletResponse.SC_OK);
} else {
httpResponse.setStatus(backpackStatusCode);
}
PrintWriter out = httpResponse.getWriter();
out.print(buffer.toString());
out.close();
} catch (Exception exception) {
if (exception instanceof IOException) {
throw (IOException) exception;
} else {
String message = "Cannot transform the result with the XSLT "
+ "located at \"" + xsltLocation + "\".";
IOException ioe = new IOException(message);
ioe.initCause(exception);
throw ioe;
}
}
}
private String getContentType(Properties outputProperties) {
String mimeType = outputProperties.getProperty("media-type");
if (mimeType == null) {
String method = outputProperties.getProperty("method");
if ("xml".equals(method)) {
mimeType = "text/xml";
} else if ("html".equals(method)) {
mimeType = "text/html";
} else if ("text".equals(method)) {
mimeType = "text/plain";
}
}
String encoding = outputProperties.getProperty("encoding");
if (mimeType != null && encoding != null) {
mimeType += "; charset=" + encoding;
}
return mimeType;
}
}