/*
* 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.wddx;
import java.io.CharArrayWriter;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringReader;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import com.naryx.tagfusion.cfm.engine.cfArrayData;
import com.naryx.tagfusion.cfm.engine.cfBooleanData;
import com.naryx.tagfusion.cfm.engine.cfCatchData;
import com.naryx.tagfusion.cfm.engine.cfData;
import com.naryx.tagfusion.cfm.engine.cfDateData;
import com.naryx.tagfusion.cfm.engine.cfNumberData;
import com.naryx.tagfusion.cfm.engine.cfQueryResultData;
import com.naryx.tagfusion.cfm.engine.cfSession;
import com.naryx.tagfusion.cfm.engine.cfStringData;
import com.naryx.tagfusion.cfm.engine.cfStructData;
import com.naryx.tagfusion.cfm.engine.cfmBadFileException;
import com.naryx.tagfusion.cfm.engine.cfmRunTimeException;
import com.naryx.tagfusion.cfm.tag.cfTag;
import com.naryx.tagfusion.cfm.tag.cfTagReturnType;
/**
* Serializes and de-serializes CFML data structures to the XML-based WDDX format.
*/
public class cfWDDX extends cfTag implements Serializable{
static final long serialVersionUID = 1;
public java.util.Map getInfo(){
return createInfo("database", "This function can convert complex CFML data structures to and from a WDDX(XML based) format.");
}
public java.util.Map[] getAttInfo(){
return new java.util.Map[] {
createAttInfo( "ATTRIBUTECOLLECTION", "A structure containing the tag attributes", "", false ),
createAttInfo("ACTION", "The type of conversion to be performed. Possible options are: \"cfml2wddx\", \"wddx2cfml\", \"cfml2js\", \"wddx2js\".", "", true ),
createAttInfo("INPUT", "The data to be converted.", "", true ),
createAttInfo("OUTPUT", "The output of a conversion. This is a required attribute when ACTION = \"wddx2cfml\".", "", false ),
createAttInfo("VERSION", "This attribute allows the selection of the WDDX version to be used. This attribute only applies when ACTION = \"cfml2wddx\".", "", false ),
createAttInfo("TOPLEVELVARIABLE", "Specifies a name for the top level javascript variable during a conversion to javascript. This is a required attribute when ACTION = \"cfml2js\" or \"wddx2js\".", "", false )
};
}
protected void defaultParameters( String _tag ) throws cfmBadFileException {
defaultAttribute( "VALIDATE", "NO" );
defaultAttribute( "USETIMEZONEINFO", "YES" );
parseTagHeader( _tag );
if (containsAttribute("ATTRIBUTECOLLECTION"))
return;
if ( !containsAttribute( "ACTION" ) )
throw newBadFileException( "Missing Attribute", "Must contain a ACTION attribute");
if ( !containsAttribute( "INPUT" ) )
throw newBadFileException( "Missing Attribute", "Must contain an INPUT attribute");
}
protected cfStructData setAttributeCollection(cfSession _Session) throws cfmRunTimeException {
cfStructData attributes = super.setAttributeCollection(_Session);
if ( !containsAttribute( attributes, "ACTION" ) )
throw newBadFileException( "Missing Attribute", "Must contain a ACTION attribute");
if ( !containsAttribute( attributes, "INPUT" ) )
throw newBadFileException( "Missing Attribute", "Must contain an INPUT attribute");
return attributes;
}
//------------------------------------------------------------
public cfTagReturnType render( cfSession _Session ) throws cfmRunTimeException {
cfStructData attributes = setAttributeCollection(_Session);
boolean processingCfOutput = _Session.setProcessingCfOutput( true );
String action = getDynamic( attributes, _Session, "ACTION" ).getString().toUpperCase();
cfData inputData = getDynamic( attributes, _Session, "INPUT" );
String output = null;
if ( action.equals("WDDX2CFML") ){
if ( !containsAttribute( attributes, "OUTPUT" ) ){
throw newBadFileException( "Missing Attribute", "WDDX2CFML Must contain an OUTPUT attribute");
}
if( inputData instanceof cfStringData ){
output = getDynamic( _Session, "OUTPUT" ).getString();
cfData cfml = wddx2Cfml( inputData.getString(), _Session );
_Session.setData( output, cfml );
} else{
throw newRunTimeException( "Input variable must be a String" );
}
}else if ( action.equals("CFML2WDDX") ){
int version = 10;
if ( containsAttribute( attributes,"VERSION") )
version = (int)(getDynamic( attributes,_Session, "VERSION").getDouble()) * 10;
String wddxString = cfml2Wddx( inputData, version );
if ( containsAttribute( attributes, "OUTPUT" ) ){
output = getDynamic( attributes, _Session, "OUTPUT" ).getString();
_Session.setData( output, new cfStringData( wddxString ) );
}else
_Session.write( wddxString );
}else if ( action.equals("WDDX2JS") ){
if ( !containsAttribute( attributes, "TOPLEVELVARIABLE" ) )
throw newRunTimeException( "Please supply a top level variable for ACTION=WDDX2JS" );
String topLevelVariable = getDynamic( attributes,_Session, "TOPLEVELVARIABLE" ).getString();
if ( containsAttribute( attributes, "OUTPUT" ) )
output = getDynamic( attributes, _Session, "OUTPUT" ).getString();
wddx2JS( inputData.getString(), _Session, output, topLevelVariable );
} else if ( action.equals("CFML2JS") ){
if ( !containsAttribute( attributes, "TOPLEVELVARIABLE" ) )
throw newRunTimeException( "Please supply a top level variable for ACTION=CFML2JS" );
String topLevelVariable = getDynamic( attributes, _Session, "TOPLEVELVARIABLE" ).getString();
if ( containsAttribute( attributes, "OUTPUT" ) )
output = getDynamic( attributes, _Session, "OUTPUT" ).getString();
cfml2JS( inputData, _Session, output, topLevelVariable );
}
_Session.setProcessingCfOutput( processingCfOutput );
return cfTagReturnType.NORMAL;
}
//--------------------------------------------------------------
//-- This method has been marked as 'public static' as it is required by the JMS tags
public static String cfml2Wddx( cfData _input ) {
return cfml2Wddx( _input, 10 );
}
public static String cfml2Wddx( cfData _input, int version ) {
CharArrayWriter outChar = new CharArrayWriter( 1024 );
PrintWriter out = new PrintWriter( outChar );
if ( version > 10 ){
out.write( "<wddxPacket version='1.1'><h></h><d>" );
_input.dumpWDDX( version, out );
out.write( "</d></wddxPacket>" );
}else{
out.write( "<wddxPacket version='1.0'><header></header><data>" );
_input.dumpWDDX( version, out );
out.write( "</data></wddxPacket>" );
}
out.flush();
return outChar.toString();
}
//--------------------------------------------------------------
public static cfData wddx2Cfml( String _wddxString, cfSession _Session ) throws cfmRunTimeException{
wddxHandler handler = new wddxHandler( _Session );//TODO: remove, _output );
SAXParserFactory factory = SAXParserFactory.newInstance();
try{
SAXParser xmlParser = factory.newSAXParser();
InputSource ip = new InputSource( new StringReader( _wddxString ));
xmlParser.parse( ip, handler );
return handler.getResult();
}catch(Exception e){
cfCatchData catchData = new cfCatchData( _Session );
catchData.setType( "WDDX" );
catchData.setDetail( "CFWDDX" );
catchData.setMessage( "Error deserializing WDDX string: " + (e instanceof NullPointerException ? "Badly Formatted xml" : e.getMessage() ) );
throw new cfmRunTimeException( catchData );
}
}
//--------------------------------------------------------------
private void wddx2JS( String _wddxString, cfSession _Session, String _output, String _topLevelVariable ) throws cfmRunTimeException{
//-- First convert the WDDX to CFML to make sure all is well there
cfData cfml = wddx2Cfml( _wddxString, _Session );
//TODO: check if cfml == null
//-- Then take the CFML, and convert it to JavaScript
cfml2JS( cfml, _Session, _output, _topLevelVariable );
}
//--------------------------------------------------------------
public static String cfml2JS( cfSession _Session, cfData _input, String _topLevelVariable ) throws cfmRunTimeException{
String resultingJavascript = "";
if ( _input.getDataType() == cfData.CFQUERYRESULTDATA ){
resultingJavascript = new wddxQueryResult( _topLevelVariable, (cfQueryResultData)_input ).getJSData();
} else if ( _input.getDataType() == cfData.CFSTRUCTDATA ){
resultingJavascript = new wddxStruct( _topLevelVariable, (cfStructData)_input ).getJSData();
} else if ( _input.getDataType() == cfData.CFARRAYDATA ){
resultingJavascript = new wddxArray( _topLevelVariable, (cfArrayData)_input ).getJSData();
} else if ( _input.getDataType() == cfData.CFSTRINGDATA ){
resultingJavascript = _topLevelVariable + " = " + wddxDataTypes.getRHSData((cfStringData)_input) + ";\n";
} else if ( _input.getDataType() == cfData.CFBOOLEANDATA ){
resultingJavascript = _topLevelVariable + " = " + wddxDataTypes.getRHSData((cfBooleanData)_input) + ";\n";
} else if ( _input.getDataType() == cfData.CFNUMBERDATA ){
resultingJavascript = _topLevelVariable + " = " + wddxDataTypes.getRHSData((cfNumberData)_input) + ";\n";
} else if ( _input.getDataType() == cfData.CFDATEDATA ){
resultingJavascript = _topLevelVariable + " = " + wddxDataTypes.getRHSData((cfDateData)_input) + ";\n";
} else {
cfCatchData catchData = new cfCatchData( _Session );
catchData.setType( "WDDX" );
catchData.setDetail( "CFWDDX" );
catchData.setMessage( "Cannot convert cfml data type to Javascript." );
throw new cfmRunTimeException( catchData );
}
return resultingJavascript;
}
private static void cfml2JS( cfData _input, cfSession _Session, String _output, String _topLevelVariable ) throws cfmRunTimeException{
String resultingJavascript = cfml2JS( _Session, _input, _topLevelVariable );
if ( _output != null )
_Session.setData( _output, new cfStringData( resultingJavascript ) );
else
_Session.write( resultingJavascript );
}
}