/*
* Copyright (C) 2000 - 2008 TagServlet Ltd
*
* This file is part of Open BlueDragon (OpenBD) CFML Server Engine.
*
* OpenBD is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Free Software Foundation,version 3.
*
* OpenBD is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenBD. If not, see http://www.gnu.org/licenses/
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with any of the JARS listed in the README.txt (or a modified version of
* (that library), containing parts covered by the terms of that JAR, the
* licensors of this Program grant you additional permission to convey the
* resulting work.
* README.txt @ http://www.openbluedragon.org/license/README.txt
*
* http://www.openbluedragon.org/
*/
package com.naryx.tagfusion.cfm.engine;
import java.io.BufferedReader;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import com.nary.util.FastMap;
import com.naryx.tagfusion.cfm.file.cfFile;
import com.naryx.tagfusion.cfm.file.cfmlFileCache;
import com.naryx.tagfusion.cfm.file.cfmlURI;
public class cfErrorData extends Object {
/**
* A map containing lists of error handlers keyed on type. The list ordering is significant
* as it reflects the ordering that the
*/
private Hashtable<String, List<cfErrorHandler>> errorHandlers;
public cfErrorData(){
errorHandlers = new Hashtable<String, List<cfErrorHandler>>();
}
public void setHandler( String _type, cfFile Template, String MailTo, String _exception ){
addHandler( new cfErrorHandler( _type.toUpperCase(), Template, MailTo, _exception ) );
}
public void setHandler( String _type, cfmlURI Template, String MailTo, String _exception ){
addHandler( new cfErrorHandler( _type.toUpperCase(), Template, MailTo, _exception ) );
}
private void addHandler( cfErrorHandler _handler ){
String type = _handler.Type;
List<cfErrorHandler> handlers = errorHandlers.get( type );
if ( handlers == null ){
handlers = new ArrayList<cfErrorHandler>();
errorHandlers.put( type, handlers );
}
if ( _handler.Exception.equalsIgnoreCase( "Any" ) ){
handlers.add( _handler ); // placed at end of list so will be matched last
}else{
handlers.add( 0, _handler );
}
}
//------------------------------------------------------
public boolean handleExceptionError( cfSession Session, cfCatchData catchData ){
cfErrorHandler eHandler = getHandler( "EXCEPTION", catchData );
if ( eHandler == null ) return false;
return eHandler.displayErrorPage(Session, catchData);
}
public boolean handleRequestError( cfSession Session, cfCatchData catchData ){
cfErrorHandler eHandler = getHandler( "REQUEST", catchData );
if ( eHandler == null ) return false;
return eHandler.displayRequestPage( Session, catchData );
}
public boolean handleValidationError( cfSession Session, String errorText ){
cfErrorHandler eHandler = getHandler( "VALIDATION", null );
if ( eHandler == null ) return false;
Map<String, String> info = new FastMap<String, String>();
info.put( "validationheader", "Form Entries Incomplete or Invalid");
info.put( "invalidfields", errorText );
info.put( "validationfooter", "Use the Back button on your web browser to return to the previous page and correct the listed problems." );
return eHandler.displayValidationPage( Session, info );
}
public boolean handleMonitorError( cfSession Session, cfCatchData catchData ){
cfErrorHandler eHandler = getHandler( "MONITOR", catchData );
if ( eHandler == null ) return false;
eHandler.displayErrorPage(Session, catchData);
return true;
}
//------------------------------------------------------
private cfErrorHandler getHandler( String Type, cfCatchData catchData ){
List<cfErrorHandler> handlers = errorHandlers.get( Type.toUpperCase() );
if ( handlers != null ){
for ( int i = 0; i < handlers.size(); i++ ){
cfErrorHandler eHandler = handlers.get(i);
if ( eHandler.useErrorPage( Type, catchData ) )
return eHandler;
}
}
return null;
}
public static void setSession( cfSession Session, cfCatchData catchData ) throws cfmRunTimeException {
setSession( Session, catchData, "" );
}
public static void setSession( cfSession Session, cfCatchData catchData, String MailTo ) throws cfmRunTimeException {
cfStructData info = new cfStructData();
info.setData( "mailto", new cfStringData( MailTo ) );
info.setData( "datetime", new cfDateData( System.currentTimeMillis() ) );
info.setData( "browser", new cfStringData(Session.REQ.getHeader("User-Agent") + "") );
info.setData( "remoteAddress", new cfStringData(Session.REQ.getRemoteAddr() + "") );
info.setData( "template", new cfStringData(Session.REQ.getRequestURI() + "") );
if ( Session.REQ.getHeader("Referer") != null )
info.setData( "httpreferer", new cfStringData(Session.REQ.getHeader("Referer") + "") );
else
info.setData( "httpreferer", new cfStringData("") );
info.setData( "generatedcontent", new cfStringData(Session.getOutputAsString()) );
if ( Session.REQ.getQueryString() != null )
info.setData( "querystring", new cfStringData( Session.REQ.getQueryString()+ "") );
else
info.setData( "querystring", new cfStringData("") );
cfData d = catchData.getData( "tagcontext" );
if ( d != null )
info.setData( "tagcontext", d );
else
info.setData( "tagcontext", cfArrayData.createArray(1) );
info.setData( "diagnostics", new cfStringData( createDiagnosticsString( catchData ) ) );
info.setData( "message", new cfStringData(catchData.getString("message")) );
info.setData( "type", catchData.getData( "type" ) );
info.setData( "errorlogfile", catchData.getData( "errorlogfile" ) );
Session.setData( "error", info );
Session.setData( "cferror", info );
}
private static String createDiagnosticsString( cfCatchData catchData ) {
StringBuilder diagnostic = new StringBuilder();
if ( catchData.containsKey( "queryerror" ) ) {
diagnostic.append( "Query Error: " );
diagnostic.append( catchData.getString( "queryerror" ) );
diagnostic.append( "\n\n" );
if ( catchData.containsKey( "datasource" ) ) {
diagnostic.append( "Datasource: " );
diagnostic.append( catchData.getString( "datasource" ) );
diagnostic.append( "\n\n" );
}
if ( catchData.containsKey( "nativeerrorcode" ) ) {
diagnostic.append( "Native Error Code: " );
diagnostic.append( catchData.getString( "nativeerrorcode" ) );
diagnostic.append( "\n\n" );
}
if ( catchData.containsKey( "sqlstate" ) ) {
String sqlState = catchData.getString( "sqlstate" );
if ( sqlState.length() > 0 ) {
diagnostic.append( "SQL State: " );
diagnostic.append( sqlState );
diagnostic.append( "\n\n" );
}
}
if ( catchData.containsKey( "sql" ) ) {
diagnostic.append( "Executing SQL: " );
diagnostic.append( catchData.getString( "sql" ) );
diagnostic.append( "\n\n" );
}
} else {
if ( catchData.containsKey( "detail" ) ) {
String detail = catchData.getString( "detail" );
if ( detail.length() > 0 ) {
diagnostic.append( "Detail: " );
diagnostic.append( detail );
diagnostic.append( "\n\n" );
}
}
if ( catchData.containsKey( "extendedinfo" ) ) {
String extendedInfo = catchData.getString( "extendedinfo" );
if ( extendedInfo.length() > 0 ) {
diagnostic.append( "Extended Info: " );
diagnostic.append( extendedInfo );
diagnostic.append( "\n\n" );
}
}
}
// add tag and line/column info
if ( catchData.containsKey( "tagcontext" ) ) {
cfArrayData tagArray = (cfArrayData)catchData.getData( "tagcontext" );
if ( ( tagArray != null ) && ( tagArray.size() > 0 ) ) {
cfStructData tagData = (cfStructData)tagArray.getElement( tagArray.size() );
if ( tagData != null ) {
diagnostic.append( "Error occurred while processing element (" );
try {
diagnostic.append( tagData.getData( "id" ).getString() );
diagnostic.append( ") on line " );
diagnostic.append( tagData.getData( "line" ).getInt() );
diagnostic.append( " column " );
diagnostic.append( tagData.getData( "column" ).getInt() );
diagnostic.append( "\n in template file \"" );
diagnostic.append( tagData.getData( "template" ).getString() );
diagnostic.append( "\"" );
} catch ( dataNotSupportedException e ) {
diagnostic.append( "ERROR CREATING DIAGNOSTIC MESSAGE: " + e );
}
}
}
}
return diagnostic.toString();
}
//---------------------------------------
class cfErrorHandler extends Object {
private String Type, MailTo, Exception;
private cfFile Template;
private cfmlURI templatePath;
public cfErrorHandler(String Type, cfFile Template, String MailTo, String Exception){
this.Type = Type;
this.Template = Template;
this.MailTo = MailTo;
if ( this.MailTo == null ) this.MailTo = "";
this.Exception = Exception;
}
public cfErrorHandler(String Type, cfmlURI _tempPath, String MailTo, String Exception){
this.Type = Type;
this.templatePath = _tempPath;
this.MailTo = MailTo;
if ( this.MailTo == null ) this.MailTo = "";
this.Exception = Exception;
}
public boolean useErrorPage(String inType, cfCatchData catchData){
if ( Type.equalsIgnoreCase( "request" ) && inType.equalsIgnoreCase("request") )
return true;
else if ( Type.equalsIgnoreCase( "validation" ) && inType.equalsIgnoreCase("validation") )
return true;
else if ( Type.equalsIgnoreCase( "exception" ) && inType.equalsIgnoreCase("exception") ){
if ( Exception.equalsIgnoreCase("Any") )
return true;
else
return Exception.equalsIgnoreCase( catchData.getString( "type" ) );
}else if ( Type.equalsIgnoreCase( "monitor" ) && inType.equalsIgnoreCase("monitor") ){
if ( Exception.equalsIgnoreCase("Any") )
return true;
else
return Exception.equalsIgnoreCase( catchData.getString( "type" ) );
}else
return false;
}
public boolean displayErrorPage( cfSession _Session, cfCatchData catchData ){
try{
//--[ Setup the dump variable
cfErrorData.setSession( _Session, catchData, MailTo );
//--[ Reset the Session output so we can discard the presently rendered stuff
if ( !Type.equalsIgnoreCase("MONITOR") ){
_Session.suspendFilter();
_Session.clearCfSettings();
try {
_Session.reset();
_Session.setContentType( "text/html" );
} catch ( cfmRunTimeException ignore ) {}
}
//--[ Render the output file
Template.render( _Session );
//--[ Flush any output left behind in the buffer out
if ( Type.equalsIgnoreCase("MONITOR") )
_Session.pageFlush();
else{
_Session.pageEnd();
}
} catch ( cfmAbortException aE ) {
_Session.pageEnd();
}catch(Exception E){ // caused an exception so return that it was unsuccessful
return false;
}
return true;
}
private Map<String, String> getBasicErrorVars( cfSession _Session, cfCatchData _catchData ){
Map<String, String> errorVars = new FastMap<String, String>();
cfData msg = _catchData.getData( "message" );
try{
errorVars.put( "diagnostics", (msg != null) ? msg.getString() : "" );
}catch( dataNotSupportedException e ){
errorVars.put( "diagnostics", "" );
}
errorVars.put( "mailto", MailTo == null ? "" : MailTo );
errorVars.put( "datetime", com.nary.util.Date.formatNow( "EEE MMM dd HH:mm:ss zzz yyyy" ) );
errorVars.put( "browser", _Session.REQ.getHeader("User-Agent") );
errorVars.put( "remoteaddress", _Session.REQ.getRemoteAddr() );
String referer = _Session.REQ.getHeader("Referer");
errorVars.put( "httpreferer", (referer == null) ? "" : referer );
errorVars.put( "template", _Session.REQ.getRequestURI() );
errorVars.put( "generatedcontent", _Session.getOutputAsString() );
String qStr = _Session.REQ.getQueryString();
errorVars.put( "querystring", (qStr == null) ? "" : qStr);
return errorVars;
}
private boolean displayValidationPage( cfSession _Session, Map<String, String> _vars ){
return displayNonCFMLPage( _Session, _vars );
}
private boolean displayRequestPage( cfSession _Session, cfCatchData catchData ){
return displayNonCFMLPage( _Session, getBasicErrorVars( _Session, catchData ) );
}
private boolean displayNonCFMLPage( cfSession _Session, Map<String, String> _vars ){
BufferedReader reader = null;
try{
reader = cfmlFileCache.getReader( _Session.REQ, _Session.CTX, templatePath );
char[] buffer = new char[2048];
StringBuilder fileContent = new StringBuilder();
int read;
while( (read = reader.read( buffer )) != -1 ){
fileContent.append( buffer, 0, read );
}
// look for valid #error.xxx# tokens ignoring them if not supported
int i = 0;
String errorPrefix = "error.";
int prefixLen = errorPrefix.length();
while ( i < fileContent.length() ){
if ( fileContent.charAt(i) == '#' ){
// read in # expression
int expStart = ++i;
while ( i < fileContent.length() && fileContent.charAt(i) != '#' ){
i++;
}
if ( i < fileContent.length() ){ // found an ending '#'
String exp = fileContent.substring( expStart, i ).toLowerCase();
if ( exp.length() > prefixLen && exp.startsWith( errorPrefix ) ){
String subexp = exp.substring( prefixLen );
String replStr = _vars.get( subexp );
if ( replStr != null ){
fileContent = fileContent.replace( expStart-1, i+1, replStr );
i = expStart + replStr.length(); // set i to correct start
}
}
}
}else{
i++;
}
}
_Session.suspendFilter();
_Session.clearCfSettings();
_Session.reset();
_Session.setContentType( "text/html" );
_Session.write( fileContent.toString() );
_Session.pageEnd();
return true;
}catch( Exception e){
return false;
}finally{
if ( reader != null ) try{reader.close();}catch(java.io.IOException ioe){}
}
}
}
}