/*
* Copyright 2000 Draagon Software, Inc. All Rights Reserved.
*
* This software is the proprietary information of Draagon Software, Inc.
* Use is subject to license terms.
*
*/
package com.draagon.wii.servlet;
import com.draagon.wii.*;
import com.draagon.wii.device.*;
import com.draagon.wii.security.*;
import com.draagon.wii.internal.*;
import com.draagon.wii.connectors.*;
import com.draagon.timers.MethodTimer;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public abstract class WIIServlet extends HttpServlet
{
private static final long serialVersionUID = 3794497409648750697L;
//protected String mWIIBase = "http://localhost:8080/servlet/wii";
// protected String mServerName = "localhost";
// protected String mPort = "80";
private WIIConfiguration mConfiguration = null;
// Caches allow a Class.findName() call only once
private Object mLock = new String();
private HashMap<String,List<WIIRequestHeaders>> mRequestHeaderCache = new HashMap<String,List<WIIRequestHeaders>>();
private HashMap<String,List<WIIResponseHeaders>> mResponseHeaderCache = new HashMap<String,List<WIIResponseHeaders>>();
private HashMap<String,Class<?>> mStreamCache = new HashMap<String,Class<?>>();
private HashMap<String,Class<?>> mServiceCache = new HashMap<String,Class<?>>();
private HashMap<String,Class<?>> mConnectorCache = new HashMap<String,Class<?>>();
//private HashMap<String,Class<?>> mResponseCache = new HashMap<String,Class<?>>();
private HashMap<String,InternalService> mInternalServiceTable = new HashMap<String,InternalService>();
protected HashMap<String,WIISite> mSiteTable = new HashMap<String,WIISite>();
// protected Properties mWIIProps = null;
protected String mServletName = "Draagon Web Integrator Servlet";
private static Log log = LogFactory.getLog( WIIServlet.class );
protected SecuritySystem mSecurity = null;
protected WIIKernel mKernel = null;
protected void initialize( ServletConfig config, WIIConfiguration c )
throws ServletException
{
ServletContext context = config.getServletContext();
// Create the Kernel and place it into the context
mKernel = new WIIKernel();
context.setAttribute( "wii.kernel", mKernel );
// Place the WIIConfiguration into the Kernel
mConfiguration = c;
context.setAttribute( "wii.configuration", mConfiguration );
// Place the WIIServlet into the Kernel
context.setAttribute( "wii.servlet", this );
if ( log.isInfoEnabled() )
{
log.info( mServletName + " has been initialized with Version: " + WIIKernel.VERSION );
log.info( "Servlet Initialized Successfully..." );
}
}
public WIIConfiguration getConfiguration()
{
return mConfiguration;
}
public WIIKernel getKernel()
{
return mKernel;
}
protected SecuritySystem getSecuritySystem()
{
if ( mSecurity != null ) return mSecurity;
mSecurity = new ServletSecurity();
return mSecurity;
}
public WIIService getService( HttpServletRequest request, HttpServletResponse response, String name )
throws ServletException, IOException
{
WIIServletRequest wiireq = getRequest( request, this );
WIIServletResponse wiires = getResponse( response );
// Set the device (Use the default device)
wiireq.setDevice( new HtmlDevice() );
if ( !loadUser( wiireq, wiires ) ) return null;
try
{
return wiireq.getWIIService( name );
}
catch( WIIException e )
{
wiireq.getDevice().returnError( wiireq, wiires, "Service Error", "Error getting service [" + name + "]: " + e.getMessage(), e );
return null;
}
}
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
MethodTimer mt = new MethodTimer( this, "service" );
WIIServletRequest wiireq = getRequest( request, this );
WIIServletResponse wiires = getResponse( response );
// Set the device (Use the default device)
wiireq.setDevice( new HtmlDevice() );
// Get the URL path to determine the external system
String path = request.getPathInfo();
if ( path == null ) path = "";
if ( path.startsWith( "/info" ))
{
wiireq.getDevice().returnMessage( wiireq, wiires, "Running", "Draagon Web Integrator running..." );
return;
}
if ( path.startsWith( "/wii/" ))
{
if ( !loadUser( wiireq, wiires ) ) return;
path = path.substring( 5 );
serviceInternalRequest( wiireq, wiires, path );
}
else
{
// Get the external system domain
WIISite site = getSite( extract( path ));
if ( site != null )
{
wiireq.setSite( site );
if ( !loadUser( wiireq, wiires ) ) return;
serviceExternalSystem( wiireq, wiires );
}
else
{
wiireq.getDevice().returnError( wiireq, wiires, "Invalid Site", "The specified external system does not exist in the wii.properties file [" + path + "]" );
return;
}
}
mt.done();
}
protected WIIServletRequest getRequest( HttpServletRequest request, WIIServlet serv )
{
return new WIIServletRequest( request, serv );
}
protected WIIServletResponse getResponse( HttpServletResponse response )
{
return new WIIServletResponse( response );
}
protected abstract boolean loadUser( WIIServletRequest request, WIIServletResponse response )
throws IOException;
protected WIISite getSite( String site )
{
if ( site == null )
{
log.error( "(loadSite) Site url is empty" );
return null;
}
WIISite s = (WIISite) mSiteTable.get( site );
if ( s != null ) return s;
// Create the new WIISite object
ServletSite d = new ServletSite();
d.setName( site );
String base = getConfiguration().getSiteProperty( d, "url" );
if ( base == null || base.equals( "" ))
{
log.error( "(loadSite) External base url not found for site: " + site );
return null;
}
d.setBase( base );
// Set the security levels
setSiteAccess( d );
mSiteTable.put( site, d );
return d;
}
public void setSiteAccess( WIISite site )
{
site.setSecuritySystem( getSecuritySystem() );
String allow = getConfiguration().getSiteProperty( site, "allow" );
if ( allow != null && !allow.equals( "" ))
site.setAccess( allow );
}
protected String extract( String url )
{
if ( url == null || url.charAt( 0 ) != '/' || url.length() < 3 )
return "ROOT";
url = url.substring( 1 );
int i = url.indexOf( '/' );
if ( i <= 0 ) return "ROOT";
url = url.substring( 0, i );
// Check to make sure it is a valid site
ServletSite d = new ServletSite();
d.setName( url );
String base = getConfiguration().getSiteProperty( d, "url" );
if ( base == null || base.equals( "" )) return "ROOT";
return url;
}
/* public Properties getWIIProperties()
{
return mWIIProps;
}*/
/* public Properties getWIIProperties()
{
return mWIIProps;
}*/
protected void serviceExternalSystem( WIIRequest osreq, WIIResponse osres )
throws ServletException, IOException
{
Exception ex = null;
try
{
WIIKernel wii = getKernel();
MethodTimer mt = new MethodTimer( wii, "serviceExternal" );
wii.serviceExternal( osreq, osres );
mt.done();
}
catch( WIIException e )
{
ex = e;
}
catch( IOException e )
{
if ( e.getMessage().indexOf( "Connection reset by peer" ) >= 0 )
{
log.warn( "Connection reset by peer: " + osreq.getSite().getExternalURL( osreq.getPathInfo() ), e );
}
else if ( e.getMessage().indexOf( "Connection aborted by peer" ) >= 0 )
{
log.warn( "Connection aborted by peer: " + osreq.getSite().getExternalURL( osreq.getPathInfo() ), e );
}
else
ex = e;
}
if ( ex != null )
{
osreq.logError( "Error processing request with external system", ex );
try
{
// try {
// ((WIIServletResponse)osres).getServletResponse().reset();
// } catch( NoSuchMethodError e ) {}
osreq.getDevice().returnError( osreq, osres, "Error Occurred", ex.getMessage(), ex );
}
catch ( Exception xex )
{
if ( log.isDebugEnabled() )
log.debug( "(serviceExternalSystem) Error processing request", ex );
}
}
}
protected void serviceInternalRequest( WIIServletRequest req, WIIServletResponse res, String path )
throws ServletException, IOException
{
if ( path == null )
{
req.getDevice().returnError( req, res, "Invalid Request", "Invalid Internal System Request [null]" );
return;
}
int i = path.indexOf( '?' );
if ( i > 0 ) path = path.substring( 0, i );
i = path.indexOf( '/' );
if ( i > 0 ) path = path.substring( 0, i );
try
{
InternalService is = getInternalService( path );
if ( is == null )
{
req.getDevice().returnError( req, res, "Invalid Internal Service", "Invalid Internal System Request [" + path + "]" );
return;
}
WIIKernel wii = getKernel();
MethodTimer mt = new MethodTimer( wii, "serviceInternal" );
//////////////////////////////////////////////////////////////
// Add the framing
// Determine the frame type
String frametype = WIITemplate.THICK;
String frame = req.getParameter( "WII_Frame" );
if ( log.isDebugEnabled() )
log.debug( "(serviceInternalRequest) WII_Frame param: [" + frame + "]" );
if ( frame != null && frame.compareToIgnoreCase( "thick" ) == 0 )
frametype = WIITemplate.THICK;
else if ( frame != null && frame.compareToIgnoreCase( "thin" ) == 0 )
frametype = WIITemplate.THIN;
else if ( frame != null && frame.compareToIgnoreCase( "none" ) == 0 )
frametype = WIITemplate.THIN; // Yes, force it to thin!
if ( log.isDebugEnabled() )
log.debug( "(serviceInternalRequest) Frame type used: " + frametype );
res.setContentType( "text/html" );
if ( req.getTemplate() != null )
{
req.getTemplate().setFrameMode( frametype );
req.getTemplate().addHeader( res );
}
//////////////////////////////////////////////////////////////
wii.serviceInternal( req, res, is );
//////////////////////////////////////////////////////////////
// Add the framing
if ( req.getTemplate() != null )
{
req.getTemplate().addFooter( res );
}
//////////////////////////////////////////////////////////////
mt.done();
}
catch( Exception e )
{
req.logError( "Error processing internal request", e );
try
{
// try {
// res.getServletResponse().reset();
// } catch( NoSuchMethodError nouse ) {}
req.getDevice().returnError( req, res, "Error Occurred", "Internal Service Request Error: " + e.getMessage(), e );
}
catch ( Exception ex )
{
if ( log.isDebugEnabled() )
log.debug( "(serviceExternalSystem) Error processing internal request", e );
}
}
}
public InternalService getInternalService( String name )
throws WIIException
{
InternalService is = mInternalServiceTable.get( name );
if ( is != null ) return is;
String cstr = getConfiguration().getInternalServiceClass( name );
if ( cstr == null || cstr.equals( "" ))
{
log.error( "(getInternalService) Internal Service not found with name: " + name );
return null;
}
try
{
Class<?> c = Class.forName( cstr );
is = (InternalService) c.newInstance();
}
catch ( Exception e )
{
log.error( "(getInternalService) Could not create Internal Service instance of class [" + cstr + "]", e );
return null;
}
is.setName( name );
setInternalServiceAccess( is );
mInternalServiceTable.put( name, is );
return is;
}
public void setInternalServiceAccess( InternalService is )
{
is.setSecuritySystem( getSecuritySystem() );
String allow = getConfiguration().getInternalServiceProperty( is, "allow" );
if ( allow != null ) is.setAccess( allow );
}
/* public String getURLBase()
{
return mURLBase;
}
*/
public String getWIIURL( WIIServletRequest req )
{
return ((WIIServletRequest)req).getServletPath();
}
public String getServletInfo()
{
return "WII Servlet";
}
public WIIService getWIIService( String name, WIISite site )
throws WIIException
{
WIIService f = null;
Class<?> c = getServiceCache( site, name );
try {
if ( c != null ) f = (WIIService) c.newInstance();
else return null;
}
catch( Exception e ) {
log.error( "(WIIServletRequest.getWIIService) Could not create Service class", e );
throw new WIIException( "(WIIServletRequest.getWIIService) Could not create Service class: " + e );
}
f.setName( name );
return f;
}
protected Class<?> getServiceCache( WIISite site, String name )
{
Class<?> tmp = null;
synchronized ( mLock )
{
String cstr = getConfiguration().getServiceClass( site, name );
if ( cstr == null ) return null;
tmp = mServiceCache.get( cstr );
if ( tmp != null ) return tmp;
try
{
tmp = Class.forName( cstr );
@SuppressWarnings("unused")
WIIService f = (WIIService) tmp.newInstance();
mServiceCache.put( cstr, tmp );
}
catch( Exception e )
{
log.error( "(WIIServletRequest.getServiceCache) Could not load service with class name [" +cstr+ "]", e );
tmp = null;
}
}
return tmp;
}
public List<WIIRequestHeaders> getWIIRequestHeaders( WIISite site )
throws WIIException
{
List<WIIRequestHeaders> tmp = null;
synchronized( mLock )
{
tmp = mRequestHeaderCache.get( site.getName() );
if ( tmp != null ) return tmp;
tmp = new ArrayList<WIIRequestHeaders>();
List<String> names = getConfiguration().getRequestHeaderClasses( site );
// System.out.println( "Number of request headers: " + names.size() );
for( String classname : names )
{
Class<?> c = null;
try {
c = Class.forName( classname );
WIIRequestHeaders o = (WIIRequestHeaders) c.newInstance();
// tmp.addElement( c );
tmp.add( o );
// System.out.println( "Added header to cache: " + c.toString() );
}
catch( Exception ex )
{
log.error( "(WIIServletRequest.getRequestHeaderCache) Could not load header class with name [" +classname+ "]", ex );
}
}
mRequestHeaderCache.put( site.getName(), tmp );
}
return tmp;
}
public List<WIIResponseHeaders> getWIIResponseHeaders( WIISite site )
throws WIIException
{
List<WIIResponseHeaders> tmp = null;
synchronized( mLock )
{
tmp = mResponseHeaderCache.get( site.getName() );
if ( tmp != null ) return tmp;
tmp = new ArrayList<WIIResponseHeaders>();
List<String> names = getConfiguration().getResponseHeaderClasses( site );
for( String classname : names )
{
Class<?> c = null;
try {
c = Class.forName( classname );
WIIResponseHeaders o = (WIIResponseHeaders) c.newInstance();
// tmp.addElement( c );
tmp.add( o );
// System.out.println( "Added header to cache: " + classname + "-" + c.toString() );
}
catch( Exception ex )
{
log.error( "(WIIServletRequest.getResponseHeaderCache) Could not load Header class with name [" +classname+ "]", ex );
}
}
mResponseHeaderCache.put( site.getName(), tmp );
}
return tmp;
}
public WIIConnector getWIIConnector( WIISite site )
throws WIIException
{
WIIConnector tmp = null;
Class<?> c = getConnectorCache( site );
if ( c == null ) return new HttpConnector();
else
{
try {
tmp = (WIIConnector) c.newInstance();
}
catch( Exception e ) {
log.error( "(WIIServletRequest.getWIIConnector) Could not create connector class", e );
throw new WIIException( "(WIIServletRequest.getWIIConnector) Could not create connector class: " + e );
}
}
return tmp;
}
protected Class<?> getConnectorCache( WIISite site )
{
Class<?> tmp = null;
synchronized( mLock )
{
tmp = mConnectorCache.get( site.getName() );
if ( tmp != null ) return tmp;
String classname = getConfiguration().getConnectorClass( site );
if ( classname == null )
{
log.error( "(WIIServletRequest.getConnectorCache) Could not load connector class, using default: com.draagon.wii.connector.HttpConnector" );
tmp = new HttpConnector().getClass();
}
else
{
try {
tmp = Class.forName( classname );
@SuppressWarnings("unused")
WIIConnector c = (WIIConnector) tmp.newInstance();
// System.out.println( "Added connector to cache: " + classname + "-" + c.toString() );
}
catch( Exception e )
{
log.error( "(WIIServletRequest.getConnectorCache) Could not load connector class with name [" +classname+ "]", e );
tmp = new HttpConnector().getClass();
}
}
mConnectorCache.put( site.getName(), tmp );
}
return tmp;
}
public WIIStream getWIIStream( WIISite site, String content )
throws WIIException
{
WIIStream tmp = null;
Class<?> c = getStreamCache( site, content );
if ( c == null ) return null;
try {
tmp = (WIIStream) c.newInstance();
}
catch( Exception ex ) {
log.error( "(WIIServletRequest.getWIIStreams) Could not create stream class", ex );
throw new WIIException( "(WIIServletRequest.getWIIStreams) Could not create stream class: " + ex );
}
return tmp;
}
protected Class<?> getStreamCache( WIISite site, String content )
{
Class<?> tmp = null;
synchronized( mLock )
{
String classname = getConfiguration().getStreamClass( site, content );
if ( classname == null ) return null;
tmp = mStreamCache.get( classname );
if ( tmp != null ) return tmp;
try {
tmp = Class.forName( classname );
@SuppressWarnings("unused")
WIIStream o = (WIIStream) tmp.newInstance();
// System.out.println( "Added stream to cache: " + classname + "-" + c.toString() );
}
catch( Exception e )
{
log.error( "(WIIServletRequest.getStreamCache) Could not load stream class with name [" +classname+ "]", e );
}
mStreamCache.put( classname, tmp );
}
return tmp;
}
}