package org.cdlib.xtf.xslt;
/*
* Copyright (c) 2004, Regents of the University of California
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the University of California nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Acknowledgements:
*
* A significant amount of new and/or modified code in this module
* was made possible by a grant from the Andrew W. Mellon Foundation,
* as part of the Melvyl Recommender Project.
*/
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.cdlib.xtf.servletBase.TextServlet;
import org.cdlib.xtf.util.XTFSaxonErrorListener;
import net.sf.saxon.FeatureKeys;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.om.AllElementStripper;
import net.sf.saxon.om.Axis;
import net.sf.saxon.om.AxisIterator;
import net.sf.saxon.om.Item;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.tinytree.TinyBuilder;
import net.sf.saxon.trans.DynamicError;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.Type;
import net.sf.saxon.value.SingletonNode;
import net.sf.saxon.value.StringValue;
import net.sf.saxon.value.Value;
/**
* Utility functions to store and access variables in the user's session.
* Also provides functions that can be called to check whether session
* tracking is enabled, and map URLs.
*
* @author Martin Haye
*/
public class Session
{
/** Checks whether session tracking was enabled in the servlet config */
public static boolean isEnabled(XPathContext context) {
return TextServlet.getCurServlet().isSessionTrackingEnabled();
} // isEnabled()
/** Function to get a data from a session variable. */
public static Value getData(XPathContext context, String name)
throws XPathException
{
HttpServletRequest req = TextServlet.getCurRequest();
HttpSession session = req.getSession(false);
if (session == null)
return null;
String val = (String)session.getAttribute(name);
if (val == null)
return null;
return getValue(context, val);
} // getData()
/** Function to put structured data into a session variable. */
public static void setData(XPathContext context, String name, Value value)
throws XPathException
{
setData(context, name, getString(context, value));
} // setData()
/** Function to put data into a session variable. */
public static void setData(XPathContext context, String name, String value)
{
// Make sure session tracking is enabled in the servlet.
if (!TextServlet.getCurServlet().isSessionTrackingEnabled()) {
throw new RuntimeException(
"Error: session tracking must be enabled in servlet config file " +
"before storing session data");
}
// Now store the value.
HttpServletRequest req = TextServlet.getCurRequest();
HttpSession session = req.getSession(true);
String oldVal = (String)session.getAttribute(name);
if (!value.equals(oldVal))
session.setAttribute(name, value);
} // setData()
/** Function to encode a URL, adding session ID if necessary. */
public static String encodeURL(XPathContext context, String origURL) {
HttpServletResponse res = TextServlet.getCurResponse();
String mappedURL = res.encodeURL(origURL);
return mappedURL;
} // encodeURL()
/** Function to get the current session's identifier */
public static String getID()
{
// Make sure session tracking is enabled in the servlet.
if (!TextServlet.getCurServlet().isSessionTrackingEnabled()) {
throw new RuntimeException(
"Error: session tracking must be enabled in servlet config file " +
"before getting session ID");
}
// Now get the session ID.
HttpServletRequest req = TextServlet.getCurRequest();
HttpSession session = req.getSession(true);
return session.getId();
} // getSessionID()
/** Function to detect if cookies are turned off */
public static boolean noCookie()
{
// Make sure session tracking is enabled in the servlet.
if (!TextServlet.getCurServlet().isSessionTrackingEnabled())
return false;
// Now check whether the ID is from a URL instead of a cookie.
HttpServletRequest req = TextServlet.getCurRequest();
return !req.isRequestedSessionIdFromCookie();
}
/**
* Gets a proper string for the value. If the value is simply a string, we
* return just that. If the value is some structured XML, we return
* XML with a header.
*
* @param context Context for the evaluation
* @return A byte stream, properly formatted
*/
public static String getString(XPathContext context, Value value)
throws XPathException
{
if (value instanceof StringValue)
return value.getStringValue();
try
{
// Convert the value to a proper NodeInfo we can examine
NodeInfo node = (NodeInfo)value.convertToJava(NodeInfo.class, context);
// Detect whether there are any elements in the document.
int nElements = 0;
AxisIterator iter = node.iterateAxis(Axis.CHILD);
while (true)
{
Item kid = iter.next();
if (kid == null)
break;
if (kid instanceof NodeInfo &&
((NodeInfo)kid).getNodeKind() == Type.ELEMENT)
{
++nElements;
}
}
// If no elements, get the simple string value.
if (nElements == 0)
return value.toString();
else if (nElements > 1) {
DynamicError err = new DynamicError(
"Error converting XML to string: there must be exactly one root element");
err.setXPathContext(context);
throw err;
}
// Convert to XML.
StringWriter writer = new StringWriter();
StreamResult streamResult = new StreamResult(writer);
TransformerFactory factory = new net.sf.saxon.TransformerFactoryImpl();
// Avoid NamePool translation, as it triggers a Saxon bug.
factory.setAttribute(FeatureKeys.NAME_POOL, node.getNamePool());
Transformer trans = factory.newTransformer();
Properties props = trans.getOutputProperties();
props.put("indent", "yes");
props.put("method", "xml");
trans.setOutputProperties(props);
// Make sure errors get directed to the right place.
if (!(trans.getErrorListener() instanceof XTFSaxonErrorListener))
trans.setErrorListener(new XTFSaxonErrorListener());
trans.transform(node, streamResult);
// All done.
String ret = writer.getBuffer().toString();
return ret;
}
catch (Exception e) {
DynamicError err = new DynamicError(
"Exception occurred converting XML to string: " + e);
err.setXPathContext(context);
throw err;
}
} // getString()
/**
* Checks if the input string is actually an XML document. If so, returns
* a value containing the parsed XML as a node. Otherwise, returns a
* simple string value.
*
* @param str The string to check.
* @return Either a SingletonNode or a StringValue.
*/
private static Value getValue(XPathContext context, String str)
throws XPathException
{
// See if we got XML.
int idx = str.indexOf("<?xml");
if (idx < 0 || idx > 10)
{
// Doesn't look like XML. Just treat it as a string.
return new StringValue(str);
}
// Ooh, we got some XML. Let's make a real Node out of it.
StreamSource src = new StreamSource(new StringReader(str));
NodeInfo doc = TinyBuilder.build(src,
new AllElementStripper(),
context.getController().getConfiguration());
return new SingletonNode(doc);
} // getValue()
} // class Session