/**
* Copyright 2011 meltmedia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xchain.framework.servlet;
import java.net.URL;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.namespace.QName;
import org.apache.commons.jxpath.JXPathContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.xml.serializer.Serializer;
import org.apache.xml.serializer.SerializerFactory;
import org.apache.xml.serializer.OutputPropertiesFactory;
import org.xchain.CatalogNotFoundException;
import org.xchain.CommandNotFoundException;
import org.xchain.framework.factory.CatalogFactory;
import org.xchain.framework.jxpath.QNameVariables;
import org.xchain.framework.lifecycle.ContainerLifecycle;
import org.xchain.framework.lifecycle.XmlFactoryLifecycle;
import org.xchain.namespaces.servlet.Constants;
import org.xchain.framework.sax.XChainDeclFilter;
import org.xchain.framework.net.UrlFactory;
import org.xchain.framework.net.UrlSourceUtil;
import org.xml.sax.InputSource;
import org.xml.sax.ErrorHandler;
import org.xml.sax.XMLReader;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* This is an INCOMPLETE servlet management interface for the xchains framework. Currently, all that this servlet supports is the rendering of xchain files with
* all xchain-stylesheet processing instructions rendered.
*
* @author Christian Trimble
* @author John Trimble
* @author Josh Kennedy
*/
public class XChainManager
extends HttpServlet
{
public static Logger log = LoggerFactory.getLogger(CatalogServlet.class);
public static final String DEFAULT_BASE_CATALOG_NAME = "resource://" + ContainerLifecycle.SERVLET_CONTEXT_ATHORITY + "/";
public static final String BASE_CATALOG_NAME_PARAM = "base-catalog-name";
protected String baseCatalogName = null;
public void init( ServletConfig config )
throws ServletException
{
super.init(config);
}
public void service( ServletRequest request, ServletResponse response )
throws ServletException, IOException
{
service((HttpServletRequest)request, (HttpServletResponse)response);
}
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, java.io.IOException
{
List<String> pathInfoSegments = pathInfoSegments(request);
if( pathInfoSegments.size() == 0 ) {
managementScreen(request, response);
return;
}
List<String> remainingSegments = pathInfoSegments.subList( 1, pathInfoSegments.size() );
String commandName = pathInfoSegments.get(0);
if( "render".equals(commandName) ) {
render(request, response, remainingSegments);
}
else {
unknownCommand(request, response, commandName);
}
}
/**
* Handles requests to the management screen.
*/
protected void managementScreen( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException
{
ServletOutputStream out = response.getOutputStream();
out.println("<html>");
out.println(" <head>");
out.println(" </head>");
out.println(" <body>");
out.println(" NOT IMPLEMENTED");
out.println(" </body>");
out.println("</html>");
}
/**
* Handles requests to the render url screen.
*/
protected void render( HttpServletRequest request, HttpServletResponse response, List<String> pathSegments )
throws ServletException, IOException
{
// get the url to render.
String systemId = request.getParameter("system-id");
if( systemId == null ) {
return;
}
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("text/xml");
URL url = null;
InputSource inputSource = null;
try {
// get the url to copy out.
url = UrlFactory.getInstance().newUrl( systemId );
// get the input source for the url.
inputSource = UrlSourceUtil.createSaxInputSource( url );
// create the XMLReader.
XMLReader reader = XmlFactoryLifecycle.newXmlReader();
reader.setErrorHandler( new FailingErrorHandler() );
// set up the source filter.
XChainDeclFilter sourceFilter = new XChainDeclFilter();
sourceFilter.setParent(reader);
sourceFilter.setErrorHandler( new FailingErrorHandler() );
// create a serializer for the response.
Properties outputProperties = OutputPropertiesFactory.getDefaultMethodProperties( "xml" );
outputProperties.setProperty("media-type", "text/xml");
Serializer serializer = SerializerFactory.getSerializer( outputProperties );
serializer.setOutputStream(response.getOutputStream());
sourceFilter.setContentHandler(serializer.asContentHandler());
// parser the url.
sourceFilter.parse(inputSource);
}
catch( Exception e ) {
errorScreen(request, response, e);
}
finally {
close(inputSource);
close(response.getOutputStream());
}
}
/**
* Handles requests to unknown command.
*/
protected void unknownCommand( HttpServletRequest request, HttpServletResponse response, String commandName )
throws ServletException, IOException
{
ServletOutputStream out = response.getOutputStream();
out.println("<html>");
out.println(" <head>");
out.println(" </head>");
out.println(" <body>");
out.println(" UNKNOWN_COMMAND:"+commandName);
out.println(" </body>");
out.println("</html>");
}
protected void errorScreen( HttpServletRequest request, HttpServletResponse response, Throwable t )
throws ServletException, IOException
{
PrintWriter out = new PrintWriter(response.getOutputStream());
t.printStackTrace(out);
}
private static List<String> pathInfoSegments(HttpServletRequest request)
{
List<String> pathInfoSegments = null;
if( request.getPathInfo() == null ) {
return Collections.emptyList();
}
String pathInfo = request.getPathInfo();
if( pathInfo.startsWith("/") ) {
pathInfo = pathInfo.substring(1);
}
return Arrays.asList(pathInfo.split("/"));
}
private static void close( InputSource inputSource )
{
try {
if( inputSource != null && inputSource.getByteStream() != null ) {
close(inputSource.getByteStream());
}
else if( inputSource != null && inputSource.getCharacterStream() != null ) {
close(inputSource.getCharacterStream());
}
}
catch( Throwable t ) {
if( log.isWarnEnabled() ) {
log.warn("Exception thrown while closing input source.");
}
}
}
public static void close( InputStream in )
{
try {
if( in != null ) {
in.close();
}
}
catch( Throwable t ) {
if( log.isWarnEnabled() ) {
log.warn("Exception thrown while closing input stream.");
}
}
}
public static void close( Reader reader )
{
try {
if( reader != null ) {
reader.close();
}
}
catch( Throwable t ) {
if( log.isWarnEnabled() ) {
log.warn("Exception thrown while closing reader.");
}
}
}
public static void close( OutputStream out )
{
try {
if( out != null ) {
out.close();
}
}
catch( Throwable t ) {
if( log.isWarnEnabled() ) {
log.warn("Exception thrown while closing output stream.");
}
}
}
public static class FailingErrorHandler
implements ErrorHandler
{
public void warning(SAXParseException exception)
throws SAXException
{
if( log.isWarnEnabled() ) {
log.warn("SAXParseException thrown while loading catalog.", exception);
}
}
public void error(SAXParseException exception)
throws SAXException
{
if( log.isErrorEnabled() ) {
log.error("SAXParseException thrown while loading catalog.", exception);
}
throw exception;
}
public void fatalError(SAXParseException exception)
throws SAXException
{
if( log.isErrorEnabled() ) {
log.error("Fatal SAXParseException thrown while loading catalog.", exception);
}
throw exception;
}
}
}