/*
* Copyright (C) 2000 - 2012 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://openbd.org/
* $Id: cfComponentData.java 2398 2013-07-28 21:19:27Z alan $
*/
package com.naryx.tagfusion.cfm.engine;
/**
* cfcInstanceData
*
* This class represents a single instance of a CFC class.
*/
import java.io.File;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javolution.util.FastList;
import com.naryx.tagfusion.cfm.application.cfAPPLICATION;
import com.naryx.tagfusion.cfm.application.cfApplicationManager;
import com.naryx.tagfusion.cfm.file.cfFile;
import com.naryx.tagfusion.cfm.parser.script.userDefinedFunction;
import com.naryx.tagfusion.cfm.tag.cfCOMPONENT;
import com.naryx.tagfusion.cfm.tag.cfDUMP;
import com.naryx.tagfusion.cfm.tag.cfFUNCTION;
public class cfComponentData extends cfComponentDataBase implements Serializable {
static final long serialVersionUID = 1;
// cfc namespace
public static final String NS_URI_CFC = "http://openbd.org/cfc";
// metaData attributes
private static final String NAME = "NAME";
private static final String FULLNAME = "FULLNAME";
private static final String PATH = "PATH";
// metaData is set within cfCOMPONENT.render()
private cfStructData metaData;
// component name
private String _componentName;
private String _componentPath;
private int _componentHash;
private int _componentType; // one of the constant values defined in cfCOMPONENT
// superclass
private cfComponentData _superComponent;
private cfFile _componentFile;
// variables scopes
private cfStructData _variablesScope = new cfStructData();
// for inheritance/implements "is-type-of" checks
private FastList<String> _polymorphNames;
private FastList<String> _polymorphPaths;
// simple constructor
public cfComponentData(cfSession session, String componentName ) throws cfmRunTimeException {
this(session, ComponentFactory.loadRawComponent(session, componentName, null ), false);
}
// simple constructor
public cfComponentData(cfSession session, String componentName, List<String> importPaths ) throws cfmRunTimeException {
this(session, ComponentFactory.loadRawComponent(session, componentName, importPaths ), false);
}
public cfComponentData(cfSession session, String componentName, boolean allowAbstract) throws cfmRunTimeException {
this(session, ComponentFactory.loadRawComponent(session, componentName, null ), allowAbstract);
}
// simple constructor
public cfComponentData(cfSession session, String componentName, List<String> importPaths, boolean allowAbstract) throws cfmRunTimeException {
this(session, ComponentFactory.loadRawComponent(session, componentName, importPaths ), allowAbstract);
}
// simple constructor
public cfComponentData(cfSession session, cfFile componentFile) throws cfmRunTimeException {
this(session, componentFile, false);
}
// real constructor
public cfComponentData(cfSession session, cfFile componentFile, boolean allowAbstract) throws cfmRunTimeException {
// save the component name
_componentHash = componentFile.hashCode();
_componentName = componentFile.getComponentName();
_componentPath = componentFile.getCfmlURI().getRealPath(session.REQ);
_componentFile = componentFile;
// set "this" scope variable defaults for Application .cfc
if (_componentName.toLowerCase().endsWith("application")) {
cfApplicationManager appManager = cfAPPLICATION.getAppManager();
this.setData(cfAPPLICATION.APPLICATIONTIMEOUT, appManager.getDefaultApplicationTimeOutData(session));
this.setData(cfAPPLICATION.CLIENTMANAGEMENT, cfBooleanData.FALSE);
this.setData(cfAPPLICATION.CLIENTSTORAGE, new cfStringData(appManager.getDefaultClientStorage()));
this.setData(cfAPPLICATION.LOGINSTORAGE, new cfStringData(cfAPPLICATION.DEFAULT_LOGIN_STORAGE));
this.setData(cfAPPLICATION.SCRIPTPROTECT, new cfStringData(""));
this.setData(cfAPPLICATION.SESSIONMANAGEMENT, cfBooleanData.FALSE);
this.setData(cfAPPLICATION.SESSIONTIMEOUT, appManager.getDefaultSessionTimeOutData(session));
this.setData(cfAPPLICATION.SETCLIENTCOOKIES, cfBooleanData.TRUE);
this.setData(cfAPPLICATION.SETDOMAINCOOKIES, cfBooleanData.FALSE);
this.setData(cfAPPLICATION.SECUREJSON, cfBooleanData.FALSE);
this.setData(cfAPPLICATION.SECUREJSONPREFIX, new cfStringData("//"));
}
// "this" scope lives inside the variables scope
_variablesScope.setData("this", this);
// render CFC pseudo-constructor (sets metadata and _componentType)
renderComponentFile(session, componentFile);
if (!allowAbstract) {
if (_componentType == cfCOMPONENT.ABSTRACT) {
throw new cfmRunTimeException(catchDataFactory.generalException(session, cfCatchData.TYPE_TEMPLATE, "Abstract Component Instantiation", "Components of TYPE=\"abstract\" cannot be instantiated directly"));
} else if (_componentType == cfCOMPONENT.INTERFACE) {
throw new cfmRunTimeException(catchDataFactory.generalException(session, cfCatchData.TYPE_TEMPLATE, "Component Interface Instantiation","Components of TYPE=\"interface\" cannot be instantiated directly"));
}
}
}
public int getComponentHash(){
return _componentHash;
}
public cfFile getComponentFile(){
return _componentFile;
}
private void renderComponentFile(cfSession session, cfFile componentFile) throws cfmRunTimeException {
enterComponent(session);
session.enterUDF(null, _superComponent, _variablesScope, false);
//This try-catch block was taken from commercial BD to fix OpenBD #178
try{
componentFile.render(session);
}catch (cfmRunTimeException e){
session.write(e.getOutput());
throw e;
}
session.leaveUDF();
leaveComponent(session);
}
// for duplicate
private cfComponentData() {}
public synchronized cfData duplicate() {
// when a CFC is instantiated, there's only one "this" scope and one
// "variables" scope
// for the entire inheritance hierarchy; the "super" scope contains only
// UDFs, which do
// not need to be duplicated; therefore, the "super" scope does not need to
// be duplicated
cfComponentData dupComponent = new cfComponentData();
dupComponent._superComponent = this._superComponent;
// duplicate the "this" scope
Object[] keys = this.keys();
for (int i = 0; i < keys.length; i++) {
String nextKey = (String) keys[i];
cfData nextData = this.getData(nextKey);
if (nextData != null) {
cfData nextDataCopy = nextData.duplicate();
if (nextDataCopy == null) { // return null if struct contains
// non-duplicatable type
return null;
}
dupComponent.setData(nextKey, nextDataCopy);
}
}
if (this._variablesScope == null) {
dupComponent._variablesScope = null;
} else {
// duplicate the "variables" scopes, ignoring the "this" scope
keys = this._variablesScope.keys();
for (int i = 0; i < keys.length; i++) {
String nextKey = (String) keys[i];
if (!nextKey.equalsIgnoreCase("this")) { // don't duplicate the "this"
// scope
cfData nextData = this._variablesScope.getData(nextKey);
if (nextData != null) {
cfData nextDataCopy = nextData.duplicate();
if (nextDataCopy == null) { // return null if struct contains
// non-duplicatable type
return null;
}
dupComponent._variablesScope.setData(nextKey, nextDataCopy);
}
}
}
// "this" scope lives inside the variables scope
dupComponent._variablesScope.setData("this", dupComponent);
}
dupComponent.metaData = (cfStructData) this.metaData.duplicate();
dupComponent._componentName = this._componentName;
dupComponent._componentPath = this._componentPath;
dupComponent._componentType = this._componentType;
return dupComponent;
}
public cfComponentData getSuperComponent() {
return _superComponent;
}
public void setSuperComponent(cfComponentData superComponent) {
_superComponent = superComponent;
}
public cfStructData getVariablesScope() {
return _variablesScope;
}
public void setVariablesScope(cfStructData newVariables) {
_variablesScope = newVariables;
}
// identify component by name
public String getComponentName() {
return _componentName;
}
public String getComponentPath() {
return _componentPath;
}
// _componentType is set within cfCOMPONENT.render() and has one of the
// constant values defined in cfCOMPONENT
public void setComponentType(int componentType) {
_componentType = componentType;
}
public int getComponentType() {
return _componentType;
}
// determine component's package path
public String getComponentPackagePath() {
int lastDot = _componentName.lastIndexOf(".");
return (lastDot > 0 ? _componentName.substring(0, lastDot) : "");
}
// identify the cfData subclass
public byte getDataType() {
return cfData.CFCOMPONENTOBJECTDATA;
}
public String getDataTypeName() {
return "component";
}
// metaData is set within cfCOMPONENT.render()
public void setMetaData(cfStructData meta) {
metaData = meta;
}
// return the component metadata
public cfStructData getMetaData() {
metaData.setData(NAME, new cfStringData(_componentName));
metaData.setData(FULLNAME, new cfStringData(_componentName));
metaData.setData(PATH, new cfStringData(_componentPath));
return metaData;
}
// check to see if this component inherits from the type specified
public boolean isTypeOf(cfSession session, String type) {
if (_polymorphNames == null) {
buildPolymorphList();
}
// first check based on component names
if (_polymorphNames.contains(type)) {
return true;
}
if (type.indexOf('.') == -1) {
type = ComponentFactory.getFullComponentName(session, type);
if (_polymorphNames.contains(type)) {
_polymorphNames.add(type);
return true;
}
}
// path-based check because a given CFC can have multiple names due to
// mappings
try {
cfFile typeFile = ComponentFactory.loadRawComponent(session, type, null);
String typePath = typeFile.getCfmlURI().getRealPath(session.REQ);
if (_polymorphPaths.contains(typePath)) {
_polymorphNames.add(type); // save the name for next time
return true;
}
} catch (cfmRunTimeException e) {
return false;
}
return false;
}
// build the list of components with which this one is polymorphic; basically
// the
// inheritance chain, plus the IMPLEMENTS list, used for "is-type-of" checking
private synchronized void buildPolymorphList() {
if (_polymorphNames != null) {
return;
}
_polymorphNames = new FastList<String>();
_polymorphNames.setValueComparator(com.nary.util.FastMap.stringComparatorIgnoreCase);
_polymorphPaths = new FastList<String>();
_polymorphPaths.setValueComparator(com.nary.util.FastMap.stringComparatorIgnoreCase);
// add this component into list
_polymorphNames.add(_componentName);
_polymorphPaths.add(_componentPath);
// add inheritance chain to the list
cfComponentData inst = _superComponent;
while (inst != null) {
// add type of super class
_polymorphNames.add(inst.getComponentName());
_polymorphPaths.add(inst.getComponentPath());
// check for next super class
inst = inst.getSuperComponent();
}
// add implements to the list
cfArrayData implementsData = (cfArrayData) metaData.getData(cfCOMPONENT.IMPLEMENTS);
if (implementsData != null) {
for (int i = 1; i <= implementsData.size(); i++) {
cfStructData interfaceData = (cfStructData) implementsData.getElement(i);
_polymorphNames.add(interfaceData.getData(NAME).toString());
_polymorphPaths.add(interfaceData.getData(PATH).toString());
}
}
}
// NOTE:
// See the warning attached to this method's overload
private void enterComponent(cfSession session) {
enterComponent(session, cfFUNCTION.EMPTY_FUNCTION);
}
// NOTE:
// It is important NOT to enter the component until just before the
// component's
// method is being called inside of the invokeComponentFunction. Doing so
// before then will most likely lead to problems evaluating the method's
// visibility cause the component to think that it is invoking a method on
// itself
// rather than from some other component or page.
private void enterComponent(cfSession session, cfFUNCTION functionTag) {
session.pushComponentData(this, functionTag);
}
// NOTE:
// It is important to enter the component right after the component's
// method is being called inside of the invokeComponentFunction. Failing to do
// will most likely lead to problems evaluating the method's visibility cause
// the component to think that it is invoking a method on itself
// rather than from some other component or page.
private static void leaveComponent(cfSession session) {
session.popComponentData();
}
// retrieve a variable value from the "this" scope
public cfData getData(cfData name) {
return getData(name.toString());
}
public cfData getData(String name) {
// check for scope names
if (isProtectedScope(name)) {
return cfNullData.NULL;
}
return super.getData(name);
}
// set a variable and value into the "this" scope
public void setData(String _key, cfData _data) {
if (isProtectedScope(_key)) {
throw new IllegalArgumentException("Cannot set CFC \"" + _key + "\" scope");
}
super.setData(_key, _data);
}
public void setData(cfData _key, cfData _data) throws cfmRunTimeException {
String keyStr = _key.toString();
// check for scope names
if (isProtectedScope(keyStr)) {
throw new dataNotSupportedException("Cannot set CFC \"" + keyStr + "\" scope");
}
super.setData(keyStr, _data);
}
public void deleteData(String _key) throws cfmRunTimeException {
if (isProtectedScope(_key)) {
throw new dataNotSupportedException("Cannot delete CFC \"" + _key + "\" scope");
}
cfData val = super.getData(_key);
if (val != null) {
super.deleteData(_key);
}
}
private userDefinedFunction getFunction(String functionName) {
cfData cfdata = this.getData(functionName);
if ((cfdata != null) && (cfdata.getDataType() == cfData.CFUDFDATA)) {
return (userDefinedFunction) cfdata;
}
return null;
}
/**
* Appliction.cfc functions differ from normal functions in that they don't
* throw an exception if the function isn't defined or not accessible.
*/
public cfData invokeApplicationFunction(cfSession session, javaMethodDataInterface method) throws cfmRunTimeException {
String methodName = method.getFunctionName();
userDefinedFunction udf = getFunction(methodName);
if (udf == null) {
return null;
}
switch (udf.getAccessType()) {
case userDefinedFunction.ACCESS_PUBLIC:
case userDefinedFunction.ACCESS_REMOTE:
return this.invokeComponentFunction(session, method, udf);
default:
return null;
}
}
public boolean isMethodAvailable( String methodName ){
return ( getFunction(methodName) != null );
}
/*
* For remote callers we want to get the return type of this method
*/
public cfFUNCTION.ReturnFormat getReturnFormat(javaMethodDataInterface method) throws cfmRunTimeException {
String methodName = method.getFunctionName();
userDefinedFunction udf = getFunction(methodName);
if (udf == null)
return cfFUNCTION.ReturnFormat.WDDX;
cfFUNCTION function = udf.getParentFunction();
return (function != null) ? function.getReturnFormat() : udf.getReturnFormat();
}
/*
* For remote callers we want to get the return the json date of this method
*/
public String getReturnJSONDate(javaMethodDataInterface method) throws cfmRunTimeException {
String methodName = method.getFunctionName();
userDefinedFunction udf = getFunction(methodName);
if (udf == null) {
return null;
}
cfFUNCTION function = udf.getParentFunction();
return (function != null) ? function.getReturnJSONDate() : udf.getReturnJSONDate();
}
public String getReturnJSONCase(javaMethodDataInterface method) throws cfmRunTimeException {
String methodName = method.getFunctionName();
userDefinedFunction udf = getFunction(methodName);
if (udf == null) {
return null;
}
cfFUNCTION function = udf.getParentFunction();
return (function != null) ? function.getReturnJSONCase() : udf.getReturnJSONCase();
}
/*
* For remote callers we want to determine if the SecureJSON flag has been set
*/
public boolean isSecureJSon(javaMethodDataInterface method) throws cfmRunTimeException {
String methodName = method.getFunctionName();
userDefinedFunction udf = getFunction(methodName);
if (udf == null) {
return false;
}
cfFUNCTION function = udf.getParentFunction();
return (function != null) ? function.isSecureJSon() : false;
}
/*
* For remote callers we want to determine if the ACCESS type is REMOTE
*/
public boolean isRemoteable(javaMethodDataInterface method) throws cfmRunTimeException {
String methodName = method.getFunctionName();
userDefinedFunction udf = getFunction(methodName);
if (udf == null) {
return false;
}else
return udf.getAccessType() == userDefinedFunction.ACCESS_REMOTE;
}
/*
* For remote callers we want to determine if the VERIFYCLIENT flag has been
* set
*/
public boolean verifyClient(javaMethodDataInterface method) throws cfmRunTimeException {
String methodName = method.getFunctionName();
userDefinedFunction udf = getFunction(methodName);
if (udf == null) {
return false;
}
cfFUNCTION function = udf.getParentFunction();
return (function != null) ? function.verifyClient() : false;
}
public cfData invokeComponentFunction(cfSession session, javaMethodDataInterface method) throws cfmRunTimeException {
String methodName = method.getFunctionName();
userDefinedFunction udf = getFunction(methodName);
if (udf == null) {
/*
* The method they were calling wasn't found, so lets see if the
* onMissingMethod has been defined
*/
udf = getFunction("onmissingmethod");
if (udf == null) {
throw new cfmRunTimeException(catchDataFactory.generalException(cfCatchData.TYPE_OBJECT, "errorCode.runtimeError", "cfdata.javaInvalidMethod",new String[] { methodName }));
} else {
method.setOnMethodMissing();
}
}
switch (udf.getAccessType()) {
case userDefinedFunction.ACCESS_PUBLIC:
case userDefinedFunction.ACCESS_REMOTE:
return this.invokeComponentFunction(session, method, udf);
case userDefinedFunction.ACCESS_PRIVATE:
cfComponentData componentData = session.getActiveComponentData(); // calling component
if ((componentData != null) && (componentData.equals(this) || // method is being called from within THIS component
componentData.isTypeOf(session, udf.getParentComponentName()))) { // calling CFC type is the same as or
// subclass of the function's parent CFC
return this.invokeComponentFunction(session, method, udf);
}
throw new cfmRunTimeException(catchDataFactory.generalException(cfCatchData.TYPE_OBJECT, "errorCode.runtimeError", "cfdata.javaInvalidMethod",
new String[] { methodName }));
case userDefinedFunction.ACCESS_PACKAGE:
componentData = session.getActiveComponentData();
// determine if method is being called from within a component
if (componentData != null) {
if (componentData.equals(this) || // method is being called from within THIS component
isSamePackage(componentData) || // components are in the same package
componentData.isTypeOf(session, getComponentPackagePath())) // calling component is a subclass of this component
{
return this.invokeComponentFunction(session, method, udf);
}
throw new cfmRunTimeException(catchDataFactory.generalException(cfCatchData.TYPE_OBJECT, "errorCode.runtimeError", "cfdata.javaInvalidMethod",new String[] { methodName }));
}
// called from a template
// TODO: what the heck is going on below here?
int lastSlash = -1;
String templatePath = null;
String componentPath = null;
templatePath = session.getRequestFile().getCfmlURI().getRealPath(session.REQ);
if (templatePath == null) {
throw new cfmRunTimeException(catchDataFactory.generalException(cfCatchData.TYPE_OBJECT, "errorCode.runtimeError", "cfdata.javaInvalidMethod",new String[] { methodName }));
}
lastSlash = templatePath.lastIndexOf(File.separatorChar);
if (lastSlash == -1) {
throw new cfmRunTimeException(catchDataFactory.generalException(cfCatchData.TYPE_OBJECT, "errorCode.runtimeError", "cfdata.javaInvalidMethod",new String[] { methodName }));
}
templatePath = templatePath.substring(0, lastSlash);
if (this._componentPath == null) {
throw new cfmRunTimeException(catchDataFactory.generalException(cfCatchData.TYPE_OBJECT, "errorCode.runtimeError", "cfdata.javaInvalidMethod",new String[] { methodName }));
}
lastSlash = -1;
componentPath = this._componentPath;
lastSlash = componentPath.lastIndexOf(File.separatorChar);
if (lastSlash == -1) {
throw new cfmRunTimeException(catchDataFactory.generalException(cfCatchData.TYPE_OBJECT, "errorCode.runtimeError", "cfdata.javaInvalidMethod",new String[] { methodName }));
}
componentPath = componentPath.substring(0, lastSlash);
if (templatePath.equals(componentPath)) {
return this.invokeComponentFunction(session, method, udf);
}
throw new cfmRunTimeException(catchDataFactory.generalException(cfCatchData.TYPE_OBJECT, "errorCode.runtimeError", "cfdata.javaInvalidMethod",new String[] { methodName }));
default: // this should never happen
throw new cfmRunTimeException(catchDataFactory.generalException(cfCatchData.TYPE_OBJECT, "errorCode.runtimeError", "cfdata.javaInvalidMethod",new String[] { methodName }));
}
}
private boolean isSamePackage(cfComponentData _otherCFC) {
// see if the packages are the same based on component names
if (_otherCFC.getComponentPackagePath().equals(this.getComponentPackagePath())) {
return true;
}
// see if the packages are the same based on component paths
String path = _componentPath.substring(0, _componentPath.lastIndexOf(File.separatorChar));
if (_otherCFC._componentPath.startsWith(path)) {
return true;
}
return false;
}
// execute a component method
private cfData invokeComponentFunction(cfSession session, javaMethodDataInterface method, userDefinedFunction udf) throws cfmRunTimeException {
cfData returnValue = null;
List<cfData> args = method.getEvaluatedArguments(session.getCFContext(), true);
if (method.isOnMethodMissing()) {
/* Repackage it up for the onMissingMethod */
cfData missingMethodName = new cfStringData(method.getFunctionName());
cfData missingMethodNameArguments = new cfStructData();
if (method instanceof cfcMethodData && ((cfcMethodData) method).hasNamedArguments()) {
cfArgStructData argData = ((cfcMethodData) method).getNamedArguments();
Iterator<String> it = argData.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
missingMethodNameArguments.setData(key, argData.getData(key));
}
} else {
for (int x = 0; x < args.size(); x++) {
missingMethodNameArguments.setData(String.valueOf(x + 1), args.get(x));
}
}
// Set the new arguments
args.clear();
args.add(missingMethodName);
args.add(missingMethodNameArguments);
}
// execute the function
cfFUNCTION function = udf.getParentFunction();
// push component information onto the session's component stack
enterComponent(session, function);
// call the method's UDF
if (method instanceof cfcMethodData && ((cfcMethodData) method).hasNamedArguments() && !method.isOnMethodMissing()) {
returnValue = udf.execute(session, ((cfcMethodData) method).getNamedArguments(), false);
} else {
returnValue = udf.execute(session, args, false);
}
// pop component information off the session's component stack
leaveComponent(session);
return returnValue;
}
public void dump(PrintWriter out) {
dump(out, false, "", cfDUMP.TOP_DEFAULT ); // SHORT dump (no UDFs)
}
public void dump(java.io.PrintWriter out, String _lbl, int _top) {
dump(out, false, _lbl, _top); // SHORT dump (no UDFs)
}
public void dumpLong(java.io.PrintWriter out) {
dump(out, true, "", cfDUMP.TOP_DEFAULT ); // LONG dump includes UDFs
}
public void dumpLong(java.io.PrintWriter out, String _lbl, int _top) {
dump(out, true, _lbl, _top ); // LONG dump includes UDFs
}
protected void dump(PrintWriter out, boolean longVersion, String _label, int _top) {
out.write("<table class='cfdump_table_object'>");
out.write("<th class='cfdump_th_object' colspan='2'>");
if (_label.length() > 0) {
out.write(_label);
out.write(" - ");
}
out.write("component ");
out.write(_componentName);
out.write(longVersion ? " [long version]" : " [short version]");
// out.write( " (" + this.hashCode() + ")" ); // useful for debugging
out.write("</th>");
// handle "this" scoped variables in a synchronized fashion
// to protect data integrity
Map<String, cfData> hashMap = super.getHashData();
synchronized (hashMap) {
dump(out, false, _top-1);
if (longVersion) {
dump(out, true, _top-1 );
}
}
out.write("</table>");
}
private void dump(PrintWriter out, boolean dumpUDF, int _top ) {
if ( _top < 1 ){
return;
}
// "this" scoped variables (non-UDF variables)
Iterator<String> itr = super.keySet().iterator();
while (itr.hasNext()) {
String name = itr.next();
if ( !isProtectedScope(name)) {
cfData datum = super.getData(name);
if (((datum.getDataType() == cfData.CFUDFDATA) && dumpUDF) || ((datum.getDataType() != cfData.CFUDFDATA) && !dumpUDF)) {
out.write("<tr><td class='cfdump_td_object'>");
out.write(name);
out.write("</td><td class='cfdump_td_value'>");
datum.dump(out, "", _top);
out.write("</td>");
}
}
}
}
private boolean isProtectedScope(String scope) {
return (scope.equalsIgnoreCase("this") || scope.equalsIgnoreCase("super"));
}
public String toString() {
StringWriter out = new StringWriter();
this.dump(new PrintWriter(out));
return out.toString();
}
// this version of equals() is for use by the CFML expression engine
public boolean equals(cfData data) {
if (data.getDataType() == cfData.CFCOMPONENTOBJECTDATA) {
return this.equals((Object) data);
}
return false;
}
public void dumpWDDX(int version, java.io.PrintWriter out) {
StringWriter sw = new StringWriter();
StringBuffer sb = sw.getBuffer();
PrintWriter pw = new PrintWriter(sw);
// open component's structure
if (version > 10)
sb.append("<s>");
else
sb.append("<struct>");
// set component name
if (version > 10) {
sb.append("<v n='componentName'>");
sb.append("<s>");
sb.append(_componentName);
sb.append("</s>");
sb.append("</v>");
// set "this" scope
sb.append("<v n='instanceVariables'>");
sb.append("<s>");
} else {
sb.append("<var name='componentName'>");
sb.append("<string>");
sb.append(_componentName);
sb.append("</string>");
sb.append("</var>");
// set "this" scope
sb.append("<var name='instanceVariables'>");
sb.append("<struct>");
}
Object[] keys = super.keys();
for (int idx = 0; idx < keys.length; idx++) {
String key = (String) keys[idx];
cfData datum = super.getData(key);
byte type = datum.getDataType();
if (type >= 1 && type <= 20) {
if (version > 10) {
sb.append("<v n='");
sb.append(key);
sb.append("'>");
super.getData(key).dumpWDDX(version, pw);
sb.append("</v>");
} else {
sb.append("<var name='");
sb.append(key);
sb.append("'>");
super.getData(key).dumpWDDX(version, pw);
sb.append("</var>");
}
}
}
if (version > 10) {
sb.append("</s>");
sb.append("</v>");
// close component's structure
sb.append("</s>");
} else {
sb.append("</struct>");
sb.append("</var>");
// close component's structure
sb.append("</struct>");
}
// flush buffer to incoming printwriter
out.write(sb.toString());
}
}