package railo.runtime;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import railo.commons.collection.HashMapPro;
import railo.commons.collection.MapFactory;
import railo.commons.collection.MapPro;
import railo.commons.io.DevNullOutputStream;
import railo.commons.lang.CFTypes;
import railo.commons.lang.ExceptionUtil;
import railo.commons.lang.Pair;
import railo.commons.lang.SizeOf;
import railo.commons.lang.StringUtil;
import railo.commons.lang.types.RefBoolean;
import railo.commons.lang.types.RefBooleanImpl;
import railo.runtime.component.ComponentLoader;
import railo.runtime.component.DataMember;
import railo.runtime.component.InterfaceCollection;
import railo.runtime.component.Member;
import railo.runtime.component.MetaDataSoftReference;
import railo.runtime.component.MetadataUtil;
import railo.runtime.component.Property;
import railo.runtime.config.ConfigImpl;
import railo.runtime.config.ConfigWeb;
import railo.runtime.config.ConfigWebImpl;
import railo.runtime.config.NullSupportHelper;
import railo.runtime.debug.DebugEntryTemplate;
import railo.runtime.dump.DumpData;
import railo.runtime.dump.DumpProperties;
import railo.runtime.dump.DumpTable;
import railo.runtime.dump.DumpUtil;
import railo.runtime.dump.SimpleDumpData;
import railo.runtime.engine.ThreadLocalPageContext;
import railo.runtime.exp.ApplicationException;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.functions.dynamicEvaluation.EvaluateComponent;
import railo.runtime.functions.system.ContractPath;
import railo.runtime.interpreter.CFMLExpressionInterpreter;
import railo.runtime.op.Caster;
import railo.runtime.op.Duplicator;
import railo.runtime.op.Operator;
import railo.runtime.op.ThreadLocalDuplication;
import railo.runtime.op.date.DateCaster;
import railo.runtime.thread.ThreadUtil;
import railo.runtime.type.ArrayImpl;
import railo.runtime.type.Collection;
import railo.runtime.type.FunctionArgument;
import railo.runtime.type.KeyImpl;
import railo.runtime.type.Sizeable;
import railo.runtime.type.Struct;
import railo.runtime.type.StructImpl;
import railo.runtime.type.UDF;
import railo.runtime.type.UDFGSProperty;
import railo.runtime.type.UDFImpl;
import railo.runtime.type.UDFPlus;
import railo.runtime.type.UDFProperties;
import railo.runtime.type.UDFPropertiesImpl;
import railo.runtime.type.cfc.ComponentAccess;
import railo.runtime.type.cfc.ComponentAccessEntryIterator;
import railo.runtime.type.cfc.ComponentAccessValueIterator;
import railo.runtime.type.comparator.ArrayOfStructComparator;
import railo.runtime.type.dt.DateTime;
import railo.runtime.type.it.StringIterator;
import railo.runtime.type.scope.Argument;
import railo.runtime.type.scope.ArgumentImpl;
import railo.runtime.type.scope.ArgumentIntKey;
import railo.runtime.type.scope.Variables;
import railo.runtime.type.util.ArrayUtil;
import railo.runtime.type.util.ComponentUtil;
import railo.runtime.type.util.KeyConstants;
import railo.runtime.type.util.ListUtil;
import railo.runtime.type.util.PropertyFactory;
import railo.runtime.type.util.StructSupport;
import railo.runtime.type.util.StructUtil;
import railo.runtime.type.util.UDFUtil;
/**
* %**%
* MUST add handling for new attributes (style, namespace, serviceportname, porttypename, wsdlfile, bindingname, and output)
*/
public final class ComponentImpl extends StructSupport implements Externalizable,ComponentAccess,coldfusion.runtime.TemplateProxy,Sizeable {
private static final long serialVersionUID = -245618330485511484L; // do not change this
/*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* Any change here must be changed in the method writeExternal,readExternal as well
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* */
private ComponentProperties properties;
private MapPro<Key,Member> _data;
private MapPro<Key,UDF> _udfs;
ComponentImpl top=this;
ComponentImpl base;
private PageSource pageSource;
private ComponentScope scope;
// for all the same
private int dataMemberDefaultAccess;
private Boolean _triggerDataMember;
// state control of component
boolean isInit=false;
private InterfaceCollection interfaceCollection;
private boolean useShadow;
private boolean entity;
boolean afterConstructor;
private Map<Key,UDF> constructorUDFs;
private boolean loaded;
private boolean hasInjectedFunctions;
public long sizeOf() {
return
SizeOf.size(properties)+
SizeOf.size(_data)+
SizeOf.size(scope)+
SizeOf.size(dataMemberDefaultAccess)+
SizeOf.size(false)+
SizeOf.size(interfaceCollection)+
SizeOf.size(useShadow)+
SizeOf.size(entity)+
SizeOf.size(afterConstructor)+
SizeOf.size(base);
}
/**
* Constructor of the Component, USED ONLY FOR DESERIALIZE
*/
public ComponentImpl() {
}
/**
* Constructor of the class
* @param componentPage
* @param output
* @param _synchronized
* @param extend
* @param implement
* @param hint
* @param dspName
* @param callPath
* @param realPath
* @param style
* @param meta
* @throws ApplicationException
*/
public ComponentImpl(ComponentPage componentPage,Boolean output,boolean _synchronized,
String extend, String implement, String hint, String dspName,String callPath, boolean realPath,
String style,StructImpl meta) throws ApplicationException {
this(componentPage,output,_synchronized,
extend, implement, hint, dspName,callPath, realPath, style,false, false,meta);
}
public ComponentImpl(ComponentPage componentPage,Boolean output,boolean _synchronized,
String extend, String implement, String hint, String dspName,String callPath, boolean realPath,
String style,boolean persistent,StructImpl meta) throws ApplicationException {
this(componentPage,output,_synchronized,
extend, implement, hint, dspName,callPath, realPath, style,persistent, false,meta);
}
public ComponentImpl(ComponentPage componentPage,Boolean output,boolean _synchronized,
String extend, String implement, String hint, String dspName,String callPath, boolean realPath,
String style,boolean persistent,boolean accessors,StructImpl meta) throws ApplicationException {
this.properties=new ComponentProperties(dspName,extend.trim(),implement,hint,output,callPath,realPath,_synchronized,null,persistent,accessors,meta);
//this.componentPage=componentPage instanceof ComponentPageProxy?componentPage:PageProxy.toProxy(componentPage);
this.pageSource=componentPage.getPageSource();
if(!StringUtil.isEmpty(style) && !"rpc".equals(style))
throw new ApplicationException("style ["+style+"] is not supported, only the following styles are supported: [rpc]");
}
@Override
public Collection duplicate(boolean deepCopy) {
ComponentImpl top= _duplicate(deepCopy,true);
setTop(top,top);
return top;
}
private ComponentImpl _duplicate( boolean deepCopy, boolean isTop) {
ComponentImpl trg=new ComponentImpl();
ThreadLocalDuplication.set(this, trg);
try{
// attributes
trg.pageSource=pageSource;
trg._triggerDataMember=_triggerDataMember;
trg.useShadow=useShadow;
trg.entity=entity;
trg.hasInjectedFunctions=hasInjectedFunctions;
trg.afterConstructor=afterConstructor;
trg.dataMemberDefaultAccess=dataMemberDefaultAccess;
trg.properties=properties.duplicate();
trg.isInit=isInit;
trg.interfaceCollection=interfaceCollection;
boolean useShadow=scope instanceof ComponentScopeShadow;
if(!useShadow)trg.scope=new ComponentScopeThis(trg);
if(base!=null){
trg.base=base._duplicate(deepCopy,false);
trg._data=trg.base._data;
trg._udfs=duplicateUTFMap(this,trg, _udfs,new HashMapPro<Key,UDF>(trg.base._udfs));
if(useShadow) trg.scope=new ComponentScopeShadow(trg,(ComponentScopeShadow)trg.base.scope,false);
}
else {
// clone data member, ignore udfs for the moment
trg._data=duplicateDataMember(trg, _data, new HashMapPro(), deepCopy);
trg._udfs=duplicateUTFMap(this,trg, _udfs,new HashMapPro<Key, UDF>());
if(useShadow) {
ComponentScopeShadow css = (ComponentScopeShadow)scope;
trg.scope=new ComponentScopeShadow(trg,duplicateDataMember(trg,css.getShadow(),MapFactory.getConcurrentMap(),deepCopy));
}
}
// at the moment this makes no sense, becuae this map is no more used after constructor has runned and for a clone the constructo is not executed, but perhaps this is used in future
if(constructorUDFs!=null){
trg.constructorUDFs=new HashMap<Collection.Key, UDF>();
addUDFS(trg, constructorUDFs, trg.constructorUDFs);
}
if(isTop) {
setTop(trg,trg);
addUDFS(trg,_data,trg._data);
if(useShadow){
addUDFS(trg,((ComponentScopeShadow)scope).getShadow(),((ComponentScopeShadow)trg.scope).getShadow());
}
}
}
finally {
// ThreadLocalDuplication.remove(this); removed "remove" to catch sisters and brothers
}
return trg;
}
private static void addUDFS(ComponentImpl trgComp, Map src, Map trg) {
Iterator it = src.entrySet().iterator();
Map.Entry entry;
Object key,value;
UDF udf;
ComponentImpl comp,owner;
boolean done;
while(it.hasNext()){
entry=(Entry) it.next();
key=entry.getKey();
value=entry.getValue();
if(value instanceof UDF) {
udf=(UDF) value;
done=false;
// get udf from _udf
owner = (ComponentImpl)udf.getOwnerComponent();
if(owner!=null) {
comp=trgComp;
do{
if(owner.pageSource==comp.pageSource)
break;
}
while((comp=comp.base)!=null);
if(comp!=null) {
value=comp._udfs.get(key);
trg.put(key, value);
done=true;
}
}
// udf with no owner
if(!done)
trg.put(key, udf.duplicate());
//print.o(owner.pageSource.getComponentName()+":"+udf.getFunctionName());
}
}
}
/**
* duplicate the datamember in the map, ignores the udfs
* @param c
* @param map
* @param newMap
* @param deepCopy
* @return
*/
public static MapPro duplicateDataMember(ComponentImpl c,MapPro map,MapPro newMap,boolean deepCopy){
Iterator it=map.entrySet().iterator();
Map.Entry entry;
Object value;
while(it.hasNext()) {
entry=(Entry) it.next();
value=entry.getValue();
if(!(value instanceof UDF)) {
if(deepCopy) value=Duplicator.duplicate(value,deepCopy);
newMap.put(entry.getKey(),value);
}
}
return newMap;
}
public static MapPro<Key, UDF> duplicateUTFMap(ComponentImpl src,ComponentImpl trg,MapPro<Key,UDF> srcMap, MapPro<Key, UDF> trgMap){
Iterator<Entry<Key, UDF>> it = srcMap.entrySet().iterator();
Entry<Key, UDF> entry;
UDF udf;
while(it.hasNext()) {
entry=it.next();
udf=entry.getValue();
if(udf.getOwnerComponent()==src) {
UDFPlus clone=(UDFPlus) entry.getValue().duplicate();
clone.setOwnerComponent(trg);
clone.setAccess(udf.getAccess());
trgMap.put(entry.getKey(),clone);
}
}
return trgMap;
}
/**
* initalize the Component
* @param pageContext
* @param componentPage
* @throws PageException
*/
public void init(PageContext pageContext, ComponentPage componentPage) throws PageException {
//this.componentPage=componentPage;
this.pageSource=componentPage.getPageSource();
// extends
if(!StringUtil.isEmpty(properties.extend)) {
base= ComponentLoader.loadComponent(pageContext,componentPage.getPageSource(),properties.extend,Boolean.TRUE,null);
}
else {
Page p=((ConfigWebImpl)pageContext.getConfig()).getBaseComponentPage(pageContext);
if(!componentPage.getPageSource().equals(p.getPageSource())) {
base=ComponentLoader.loadComponent(pageContext,p,p.getPageSource(),"Component",false);
}
}
if(base!=null){
this.dataMemberDefaultAccess=base.dataMemberDefaultAccess;
this._triggerDataMember=base._triggerDataMember;
_data=base._data;
_udfs=new HashMapPro<Key,UDF>(base._udfs);
setTop(this,base);
}
else {
this.dataMemberDefaultAccess=pageContext.getConfig().getComponentDataMemberDefaultAccess();
// TODO get per CFC setting this._triggerDataMember=pageContext.getConfig().getTriggerComponentDataMember();
_udfs=new HashMapPro<Key,UDF>();
_data=MapFactory.getConcurrentMap();
}
// implements
if(!StringUtil.isEmpty(properties.implement)) {
interfaceCollection=new InterfaceCollection((PageContextImpl)pageContext,getPageSource(),properties.implement);
}
// scope
if(useShadow=pageContext.getConfig().useComponentShadow()) {
if(base==null) scope=new ComponentScopeShadow(this,MapFactory.getConcurrentMap());
else scope=new ComponentScopeShadow(this,(ComponentScopeShadow)base.scope,false);
}
else {
scope=new ComponentScopeThis(this);
}
initProperties();
}
public void checkInterface(PageContext pc, ComponentPage componentPage) throws PageException {
if(interfaceCollection==null || interfaceCollection.lastUpdate()<=componentPage.lastCheck()) return;
Iterator it = interfaceCollection.getUdfs().entrySet().iterator();
Map.Entry entry;
UDFPlus iUdf,cUdf;
FunctionArgument[] iFA,cFA;
while(it.hasNext()){
entry=(Entry) it.next();
iUdf=(UDFPlus) entry.getValue();
cUdf=(UDFPlus) _udfs.get(entry.getKey());
// UDF does not exist
if(cUdf==null ) {
throw new ExpressionException(
"component ["+componentPage.getPageSource().getDisplayPath()+
"] does not implement the function ["+iUdf.toString().toLowerCase()+"] of the interface ["+
iUdf.getPageSource().getDisplayPath()+"]");
}
iFA=iUdf.getFunctionArguments();
cFA=cUdf.getFunctionArguments();
// access
if(cUdf.getAccess()>Component.ACCESS_PUBLIC){
throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
"access ["+ComponentUtil.toStringAccess(cUdf.getAccess())+"] has to be at least [public]");
}
// return type
if(iUdf.getReturnType()!=cUdf.getReturnType()){
throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
"return type ["+cUdf.getReturnTypeAsString()+"] does not match interface function return type ["+iUdf.getReturnTypeAsString()+"]");
}
// none base types
if(iUdf.getReturnType()==CFTypes.TYPE_UNKNOW && !iUdf.getReturnTypeAsString().equalsIgnoreCase(cUdf.getReturnTypeAsString())) {
throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
"return type ["+cUdf.getReturnTypeAsString()+"] does not match interface function return type ["+iUdf.getReturnTypeAsString()+"]");
}
// output
if(iUdf.getOutput()!=cUdf.getOutput()){
throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
"output does not match interface function output definition");
}
// arguments
if(iFA.length!=cFA.length) {
throw new ExpressionException( _getErrorMessage(cUdf,iUdf),"not the same argument count");
}
for(int i=0;i<iFA.length;i++) {
// type
if(iFA[i].getType()!=cFA[i].getType()){
throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
"argument type ["+cFA[i].getTypeAsString()+"] does not match interface function argument type ["+iFA[i].getTypeAsString()+"]");
}
// none base types
if(iFA[i].getType()==CFTypes.TYPE_UNKNOW && !iFA[i].getTypeAsString().equalsIgnoreCase(cFA[i].getTypeAsString())) {
throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
"argument type ["+cFA[i].getTypeAsString()+"] does not match interface function argument type ["+iFA[i].getTypeAsString()+"]");
}
// name
if(!iFA[i].getName().equalsIgnoreCase(cFA[i].getName())){
throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
"argument name ["+cFA[i].getName()+"] does not match interface function argument name ["+iFA[i].getName()+"]");
}
// required
if(iFA[i].isRequired()!=cFA[i].isRequired()){
throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
"argument ["+cFA[i].getName()+"] should "+(iFA[i].isRequired()?"":"not ")+"be required");
}
}
}
componentPage.ckecked();
}
private String _getErrorMessage(UDFPlus cUdf,UDFPlus iUdf) {
return "function ["+cUdf.toString().toLowerCase()+"] of component " +
"["+pageSource.getDisplayPath()+"]" +
" does not match the function declaration ["+iUdf.toString().toLowerCase()+"] of the interface " +
"["+iUdf.getPageSource().getDisplayPath()+"]";
}
private static void setTop(ComponentImpl top,ComponentImpl trg) {
while(trg!=null){
trg.top=top;
trg=trg.base;
}
}
Object _call(PageContext pc, Collection.Key key, Struct namedArgs, Object[] args,boolean superAccess) throws PageException {
Member member=getMember(pc,key,false, superAccess);
if(member instanceof UDFPlus) {
return _call(pc,key,(UDFPlus)member,namedArgs,args);
}
return onMissingMethod(pc, -1, member, key.getString(), args, namedArgs, superAccess);
}
Object _call(PageContext pc, int access, Collection.Key key, Struct namedArgs, Object[] args,boolean superAccess) throws PageException {
Member member=getMember(access,key,false,superAccess);
if(member instanceof UDF) {
return _call(pc,key,(UDFPlus)member,namedArgs,args);
}
return onMissingMethod(pc, access, member, key.getString(), args, namedArgs, superAccess);
}
public Object onMissingMethod(PageContext pc, int access,Member member,String name,Object _args[],Struct _namedArgs, boolean superAccess) throws PageException {
Member ommm = access==-1?
getMember(pc,KeyConstants._onmissingmethod,false, superAccess):
getMember(access,KeyConstants._onmissingmethod,false, superAccess);
if(ommm instanceof UDF) {
Argument args=new ArgumentImpl();
if(_args!=null) {
for(int i=0;i<_args.length;i++) {
args.setEL(ArgumentIntKey.init(i+1), _args[i]);
}
}
else if(_namedArgs!=null) {
UDFUtil.argumentCollection(_namedArgs, new FunctionArgument[]{});
Iterator<Entry<Key, Object>> it = _namedArgs.entryIterator();
Entry<Key, Object> e;
while(it.hasNext()){
e = it.next();
args.setEL(e.getKey(),e.getValue());
}
}
//Struct newArgs=new StructImpl(StructImpl.TYPE_SYNC);
//newArgs.setEL(MISSING_METHOD_NAME, name);
//newArgs.setEL(MISSING_METHOD_ARGS, args);
Object[] newArgs=new Object[]{name,args};
return _call(pc,KeyConstants._onmissingmethod,(UDFPlus)ommm,null,newArgs);
}
if(member==null)throw ComponentUtil.notFunction(this, KeyImpl.init(name), null,access);
throw ComponentUtil.notFunction(this, KeyImpl.init(name), member.getValue(),access);
}
Object _call(PageContext pc, Collection.Key calledName,UDFPlus udf, Struct namedArgs, Object[] args) throws PageException {
Object rtn=null;
Variables parent=null;
// INFO duplicate code is for faster execution -> less contions
// debug yes
if(pc.getConfig().debug()) {
DebugEntryTemplate debugEntry=pc.getDebugger().getEntry(pc,pageSource,udf.getFunctionName());//new DebugEntry(src,udf.getFunctionName());
int currTime=pc.getExecutionTime();
long time=System.nanoTime();
// sync yes
if(top.properties._synchronized){
synchronized (this) {
try {
parent=beforeCall(pc);
if(args!=null)rtn=udf.call(pc,calledName,args,true);
else rtn=udf.callWithNamedValues(pc,calledName,namedArgs,true);
}
finally {
pc.setVariablesScope(parent);
int diff= ((int)(System.nanoTime()-time)-(pc.getExecutionTime()-currTime));
pc.setExecutionTime(pc.getExecutionTime()+diff);
debugEntry.updateExeTime(diff);
}
}
}
// sync no
else {
try {
parent=beforeCall(pc);
if(args!=null)rtn=udf.call(pc,calledName,args,true);
else rtn=udf.callWithNamedValues(pc,calledName,namedArgs,true);
}
finally {
pc.setVariablesScope(parent);
int diff= ((int)(System.nanoTime()-time)-(pc.getExecutionTime()-currTime));
pc.setExecutionTime(pc.getExecutionTime()+diff);
debugEntry.updateExeTime(diff);
}
}
}
// debug no
else {
// sync yes
if(top.properties._synchronized){
synchronized (this) {
try {
parent=beforeCall(pc);
if(args!=null)rtn=udf.call(pc,calledName,args,true);
else rtn=udf.callWithNamedValues(pc,calledName,namedArgs,true);
}
finally {
pc.setVariablesScope(parent);
}
}
}
// sync no 385|263
else {
try {
parent=beforeCall(pc);
if(args!=null)rtn=udf.call(pc,calledName,args,true);
else rtn=udf.callWithNamedValues(pc,calledName,namedArgs,true);
}
finally {
pc.setVariablesScope(parent);
}
}
}
return rtn;
}
/**
* will be called before executing method or constructor
* @param pc
* @return the old scope map
*/
public Variables beforeCall(PageContext pc) {
Variables parent=pc.variablesScope();
pc.setVariablesScope(scope);
return parent;
}
/**
* will be called after invoking constructor, only invoked by constructor (component body execution)
* @param pc
* @param parent
*/
public void afterConstructor(PageContext pc, Variables parent) {
pc.setVariablesScope(parent);
this.afterConstructor=true;
if(constructorUDFs!=null){
Iterator<Entry<Key, UDF>> it = constructorUDFs.entrySet().iterator();
Map.Entry<Key, UDF> entry;
Key key;
UDFPlus udf;
while(it.hasNext()){
entry=it.next();
key=entry.getKey();
udf=(UDFPlus) entry.getValue();
registerUDF(key, udf,false,true);
}
}
}
/**
* this function may be called by generated code inside a ra file
* @deprecated replaced with <code>afterConstructor(PageContext pc, Variables parent)</code>
* @param pc
* @param parent
*/
public void afterCall(PageContext pc, Variables parent) {
afterConstructor(pc, parent);
}
/**
* sets the callpath
* @param callPath
* /
public void setCallPath(String callPath) {
properties.callPath=callPath;
}*/
/**
* rerturn the size
* @param access
* @return size
*/
public int size(int access) {
return keys(access).length;
}
/**
* list of keys
* @param c
* @param access
* @param doBase
* @return key set
*/
public Set<Key> keySet(int access) {
HashSet<Key> set=new HashSet<Key>();
Map.Entry<Key, Member> entry;
Iterator<Entry<Key, Member>> it = _data.entrySet().iterator();
while(it.hasNext()) {
entry=it.next();
if(entry.getValue().getAccess()<=access)set.add(entry.getKey());
}
return set;
}
/*protected Set<Key> udfKeySet(int access) {
Set<Key> set=new HashSet<Key>();
Member m;
Map.Entry<Key, UDF> entry;
Iterator<Entry<Key, UDF>> it = _udfs.entrySet().iterator();
while(it.hasNext()) {
entry= it.next();
m=entry.getValue();
if(m.getAccess()<=access)set.add(entry.getKey());
}
return set;
}*/
protected java.util.List<Member> getMembers(int access) {
java.util.List<Member> members=new ArrayList<Member>();
Member e;
Iterator<Entry<Key, Member>> it = _data.entrySet().iterator();
while(it.hasNext()) {
e=it.next().getValue();
if(e.getAccess()<=access)members.add(e);
}
return members;
}
@Override
public Iterator<Collection.Key> keyIterator(int access) {
return keySet(access).iterator();
}
@Override
public Iterator<String> keysAsStringIterator(int access) {
return new StringIterator(keys(access));
}
@Override
public Iterator<Entry<Key, Object>> entryIterator(int access) {
return new ComponentAccessEntryIterator(this, keys(access),access);
}
@Override
public Iterator<Object> valueIterator(int access) {
return new ComponentAccessValueIterator(this,keys(access),access);
}
@Override
public Iterator<Object> valueIterator() {
return valueIterator(getAccess(ThreadLocalPageContext.get()));
}
@Override
public Collection.Key[] keys(int access) {
Set<Key> set = keySet(access);
return set.toArray(new Collection.Key[set.size()]);
}
@Override
public void clear() {
_data.clear();
_udfs.clear();
}
@Override
public Member getMember(int access,Collection.Key key, boolean dataMember,boolean superAccess) {
// check super
if(dataMember && access==ACCESS_PRIVATE && key.equalsIgnoreCase(KeyConstants._super)) {
return SuperComponent.superMember((ComponentImpl)ComponentUtil.getActiveComponent(ThreadLocalPageContext.get(),this)._base());
//return SuperComponent . superMember(base);
}
if(superAccess) {
return _udfs.get(key);
}
// check data
Member member=_data.get(key);
if(member!=null) {
if(member.getAccess()<=access)return member;
return null;
}
return null;
}
/**
* get entry matching key
* @param access
* @param keyLowerCase key lower case (case sensitive)
* @param doBase do check also base component
* @param dataMember do also check if key super
* @return matching entry if exists otherwise null
*/
protected Member getMember(PageContext pc, Collection.Key key, boolean dataMember,boolean superAccess) {
// check super
if(dataMember && isPrivate(pc) && key.equalsIgnoreCase(KeyConstants._super)) {
return SuperComponent.superMember((ComponentImpl)ComponentUtil.getActiveComponent(pc,this)._base());
}
if(superAccess)
return _udfs.get(key);
// check data
Member member=_data.get(key);
if(isAccessible(pc,member)) return member;
return null;
}
private boolean isAccessible(PageContext pc, Member member) {
// TODO geschwindigkeit
if(member!=null) {
int access=member.getAccess();
if(access<=ACCESS_PUBLIC) return true;
else if(access==ACCESS_PRIVATE && isPrivate(pc)) return true;
else if(access==ACCESS_PACKAGE && isPackage(pc)) return true;
}
return false;
}
private boolean isAccessible(PageContext pc, int access) {
if(access<=ACCESS_PUBLIC) return true;
else if(access==ACCESS_PRIVATE && isPrivate(pc)) return true;
else if(access==ACCESS_PACKAGE && isPackage(pc)) return true;
return false;
}
/**
* @param pc
* @return returns if is private
*/
private boolean isPrivate(PageContext pc) {
if(pc==null) return true;
Component ac = pc.getActiveComponent();
return (ac!=null && (ac==this ||
((ComponentImpl)ac).top.pageSource.equals(top.pageSource))) ;
}
/**
* @param pc
* @return returns if is package
*/
private boolean isPackage(PageContext pc) {
Component ac = pc.getActiveComponent();
if(ac!=null) {
if(ac==this) return true;
ComponentImpl aci = ((ComponentImpl)ac);
if(aci.top.pageSource.equals(top.pageSource))return true;
int index;
String other=aci.top.getAbsName();
index=other.lastIndexOf('.');
if(index==-1)other="";
else other=other.substring(0,index);
String my=top.getAbsName();
index=my.lastIndexOf('.');
if(index==-1)my="";
else my=my.substring(0,index);
return my.equalsIgnoreCase(other);
}
return false;
}
/**
* return the access of a member
* @param key
* @return returns the access (Component.ACCESS_REMOTE, ACCESS_PUBLIC, ACCESS_PACKAGE,Component.ACCESS_PRIVATE)
*/
private int getAccess(Collection.Key key){
Member member=getMember(ACCESS_PRIVATE,key,false,false);
if(member==null) return Component.ACCESS_PRIVATE;
return member.getAccess();
}
/**
* returns current access to this component
* @param pc
* @return access
*/
private int getAccess(PageContext pc) {
if(pc==null) return ACCESS_PUBLIC;
if(isPrivate(pc)) return ACCESS_PRIVATE;
if(isPackage(pc)) return ACCESS_PACKAGE;
return ACCESS_PUBLIC;
}
@Override
public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
return toDumpData(pageContext,maxlevel,dp,getAccess(pageContext));
}
/**
* to html output print only with access less than given access
* @param pageContext
* @param access
* @return html output
*/
public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp, int access) {
DumpTable table = new DumpTable("component","#99cc99","#ccffcc","#000000");
table.setTitle("Component "+getCallPath()+""+(" "+StringUtil.escapeHTML(top.properties.dspName)));
table.setComment("Only the functions and data members that are accessible from your location are displayed");
if(top.properties.extend.length()>0)table.appendRow(1,new SimpleDumpData("Extends"),new SimpleDumpData(top.properties.extend));
if(top.properties.hint.trim().length()>0)table.appendRow(1,new SimpleDumpData("Hint"),new SimpleDumpData(top.properties.hint));
DumpTable content = _toDumpData(top,pageContext,maxlevel,dp,access);
if(!content.isEmpty())table.appendRow(1,new SimpleDumpData(""),content);
return table;
}
static DumpTable _toDumpData(ComponentImpl ci,PageContext pc, int maxlevel, DumpProperties dp,int access) {
maxlevel--;
ComponentWrap cw=new ComponentWrap(Component.ACCESS_PRIVATE, ci);
Collection.Key[] keys= cw.keys();
DumpTable[] accesses=new DumpTable[4];
accesses[Component.ACCESS_PRIVATE] = new DumpTable("#ff6633","#ff9966","#000000");
accesses[Component.ACCESS_PRIVATE].setTitle("private");
accesses[Component.ACCESS_PRIVATE].setWidth("100%");
//accesses[Component.ACCESS_PRIVATE].setRow(1,"100%");
accesses[Component.ACCESS_PACKAGE] = new DumpTable("#ff9966","#ffcc99","#000000");
accesses[Component.ACCESS_PACKAGE].setTitle("package");
accesses[Component.ACCESS_PACKAGE].setWidth("100%");
accesses[Component.ACCESS_PUBLIC] = new DumpTable("#ffcc99","#ffffcc","#000000");
accesses[Component.ACCESS_PUBLIC].setTitle("public");
accesses[Component.ACCESS_PUBLIC].setWidth("100%");
accesses[Component.ACCESS_REMOTE] = new DumpTable("#ccffcc","#ffffff","#000000");
accesses[Component.ACCESS_REMOTE].setTitle("remote");
accesses[Component.ACCESS_REMOTE].setWidth("100%");
Collection.Key key;
for(int i=0;i<keys.length;i++) {
key=keys[i];
int a=ci.getAccess(key);
DumpTable box=accesses[a];
Object o=cw.get(key,null);
if(o==ci)o="[this]";
if(DumpUtil.keyValid(dp,maxlevel, key))
box.appendRow(1,new SimpleDumpData(key.getString()),DumpUtil.toDumpData(o,pc,maxlevel,dp));
}
DumpTable table=new DumpTable("#ffffff","#cccccc","#000000");
// properties
if(ci.top.properties.persistent || ci.top.properties.accessors){
Property[] properties=ci.getProperties(false);
DumpTable prop = new DumpTable("#99cc99","#ccffcc","#000000");
prop.setTitle("Properties");
prop.setWidth("100%");
Property p;
Object child;
for(int i=0;i<properties.length;i++) {
p=properties[i];
child = ci.scope.get(KeyImpl.init(p.getName()),null);
DumpData dd;
if(child instanceof Component) {
DumpTable t = new DumpTable("component","#99cc99","#ffffff","#000000");
t.appendRow(1,new SimpleDumpData("Component"),new SimpleDumpData(((Component)child).getCallName()));
dd=t;
}
else
dd=DumpUtil.toDumpData(child, pc, maxlevel-1, dp);
prop.appendRow(1, new SimpleDumpData(p.getName()),dd);
}
if(access>=ACCESS_PUBLIC && !prop.isEmpty()) {
table.appendRow(0,prop);
}
}
if(!accesses[ACCESS_REMOTE].isEmpty()) {
table.appendRow(0,accesses[Component.ACCESS_REMOTE]);
}
if(!accesses[ACCESS_PUBLIC].isEmpty()) {
table.appendRow(0,accesses[Component.ACCESS_PUBLIC]);
}
if(!accesses[ACCESS_PACKAGE].isEmpty()) {
table.appendRow(0,accesses[Component.ACCESS_PACKAGE]);
}
if(!accesses[ACCESS_PRIVATE].isEmpty()) {
table.appendRow(0,accesses[Component.ACCESS_PRIVATE]);
}
return table;
}
/**
* @return return call path
*/
protected String getCallPath() {
if(StringUtil.isEmpty(top.properties.callPath)) return getName();
try {
return "("+ListUtil.arrayToList(ListUtil.listToArrayTrim(top.properties.callPath.replace('/','.').replace('\\','.'),"."),".")+")";
} catch (PageException e) {
return top.properties.callPath;
}
}
@Override
public String getDisplayName() {
return top.properties.dspName;
}
@Override
public String getExtends() {
return top.properties.extend;
}
public String getBaseAbsName() {
return top.base.pageSource.getComponentName();
}
public boolean isBasePeristent() {
return top.base!=null && top.base.properties.persistent;
}
@Override
public String getHint() {
return top.properties.hint;
}
@Override
public String getWSDLFile() {
return top.properties.getWsdlFile();
}
@Override
public String getName() {
if(top.properties.callPath==null) return "";
return ListUtil.last(top.properties.callPath,"./",true);
}
public String _getName() { // MUST nicht so toll
if(properties.callPath==null) return "";
return ListUtil.last(properties.callPath,"./",true);
}
public PageSource _getPageSource() {
return pageSource;
}
@Override
public String getCallName() {
return top.properties.callPath;
}
@Override
public String getAbsName() {
return top.pageSource.getComponentName();
}
@Override
public boolean getOutput() {
if(top.properties.output==null) return true;
return top.properties.output.booleanValue();
}
@Override
public boolean instanceOf(String type) {
ComponentImpl c=top;
do {
if(type.equalsIgnoreCase(c.properties.callPath)) return true;
if(type.equalsIgnoreCase(c.pageSource.getComponentName())) return true;
if(type.equalsIgnoreCase(c._getName())) return true;
// check interfaces
if(c.interfaceCollection!=null){
InterfaceImpl[] interfaces = c.interfaceCollection.getInterfaces();
if(interfaces!=null)for(int i=0;i<interfaces.length;i++){
if(interfaces[i].instanceOf(type))return true;
}
}
c=c.base;
}
while(c!=null);
if(StringUtil.endsWithIgnoreCase(type, "component")){
if(type.equalsIgnoreCase("component")) return true;
if(type.equalsIgnoreCase("web-inf.cftags.component")) return true;
//if(type.equalsIgnoreCase("web-inf.railo.context.component")) return true;
}
return false;
}
public boolean equalTo(String type) {
ComponentImpl c=top;
if(type.equalsIgnoreCase(c.properties.callPath)) return true;
if(type.equalsIgnoreCase(c.pageSource.getComponentName())) return true;
if(type.equalsIgnoreCase(c._getName())) return true;
// check interfaces
if(c.interfaceCollection!=null){
InterfaceImpl[] interfaces = c.interfaceCollection.getInterfaces();
if(interfaces!=null)for(int i=0;i<interfaces.length;i++){
if(interfaces[i].instanceOf(type))return true;
}
}
if(StringUtil.endsWithIgnoreCase(type, "component")){
if(type.equalsIgnoreCase("component")) return true;
if(type.equalsIgnoreCase("web-inf.cftags.component")) return true;
}
return false;
}
@Override
public boolean isValidAccess(int access) {
return !(access <0 || access>ACCESS_COUNT);
}
@Override
public PageSource getPageSource() {
return top.pageSource;
}
@Override
public String castToString() throws PageException {
return castToString(false);
}
@Override
public String castToString(String defaultValue) {
return castToString(false,defaultValue);
}
String castToString(boolean superAccess) throws PageException {
// magic function
PageContext pc = ThreadLocalPageContext.get();
if(pc!=null) {
Member member = getMember(pc,KeyConstants.__toString,true,superAccess);
//Object o = get(pc,"_toString",null);
if(member instanceof UDFPlus) {
UDFPlus udf = (UDFPlus)member;
if(udf.getReturnType()==CFTypes.TYPE_STRING && udf.getFunctionArguments().length==0) {
return Caster.toString(_call(pc, KeyConstants.__toString,udf, null, new Object[0]));
}
}
}
throw ExceptionUtil.addHint(new ExpressionException("Can't cast Component ["+getName()+"] to String"),"Add a User-Defined-Function to Component with the following pattern [_toString():String] to cast it to a String or use Built-In-Function \"serialize(Component):String\" to convert it to a serialized String");
}
String castToString(boolean superAccess,String defaultValue) {
// magic function
PageContext pc = ThreadLocalPageContext.get();
if(pc!=null) {
Member member = getMember(pc,KeyConstants.__toString,true,superAccess);
//Object o = get(pc,"_toString",null);
if(member instanceof UDFPlus) {
UDFPlus udf = (UDFPlus)member;
if(udf.getReturnType()==CFTypes.TYPE_STRING && udf.getFunctionArguments().length==0) {
try {
return Caster.toString(_call(pc,KeyConstants.__toString, udf, null, new Object[0]),defaultValue);
} catch (PageException e) {
return defaultValue;
}
}
}
}
return defaultValue;
}
@Override
public boolean castToBooleanValue() throws PageException {
return castToBooleanValue(false);
}
@Override
public Boolean castToBoolean(Boolean defaultValue) {
return castToBoolean(false, defaultValue);
}
boolean castToBooleanValue(boolean superAccess) throws PageException {
// magic function
PageContext pc = ThreadLocalPageContext.get();
if(pc!=null) {
Member member = getMember(pc,KeyConstants.__toBoolean,true,superAccess);
//Object o = get(pc,"_toBoolean",null);
if(member instanceof UDFPlus) {
UDFPlus udf = (UDFPlus)member;
if(udf.getReturnType()==CFTypes.TYPE_BOOLEAN && udf.getFunctionArguments().length==0) {
return Caster.toBooleanValue(_call(pc, KeyConstants.__toBoolean,udf, null, new Object[0]));
}
}
}
throw ExceptionUtil.addHint(new ExpressionException("Can't cast Component ["+getName()+"] to a boolean value"),
"Add a User-Defined-Function to Component with the following pattern [_toBoolean():boolean] to cast it to a boolean value");
}
Boolean castToBoolean(boolean superAccess,Boolean defaultValue) {
// magic function
PageContext pc = ThreadLocalPageContext.get();
if(pc!=null) {
Member member = getMember(pc,KeyConstants.__toBoolean,true,superAccess);
//Object o = get(pc,"_toBoolean",null);
if(member instanceof UDFPlus) {
UDFPlus udf = (UDFPlus)member;
if(udf.getReturnType()==CFTypes.TYPE_BOOLEAN && udf.getFunctionArguments().length==0) {
try {
return Caster.toBoolean(_call(pc,KeyConstants.__toBoolean, udf, null, new Object[0]),defaultValue);
} catch (PageException e) {
return defaultValue;
}
}
}
}
return defaultValue;
}
@Override
public double castToDoubleValue() throws PageException {
return castToDoubleValue(false);
}
@Override
public double castToDoubleValue(double defaultValue) {
return castToDoubleValue(false, defaultValue);
}
double castToDoubleValue(boolean superAccess) throws PageException {
// magic function
PageContext pc = ThreadLocalPageContext.get();
if(pc!=null) {
Member member = getMember(pc,KeyConstants.__toNumeric,true,superAccess);
//Object o = get(pc,"_toNumeric",null);
if(member instanceof UDFPlus) {
UDFPlus udf = (UDFPlus)member;
if(udf.getReturnType()==CFTypes.TYPE_NUMERIC && udf.getFunctionArguments().length==0) {
return Caster.toDoubleValue(_call(pc, KeyConstants.__toNumeric,udf, null, new Object[0]));
}
}
}
throw ExceptionUtil.addHint(new ExpressionException("Can't cast Component ["+getName()+"] to a numeric value"),
"Add a User-Defined-Function to Component with the following pattern [_toNumeric():numeric] to cast it to a numeric value");
}
double castToDoubleValue(boolean superAccess,double defaultValue) {
// magic function
PageContext pc = ThreadLocalPageContext.get();
if(pc!=null) {
Member member = getMember(pc,KeyConstants.__toNumeric,true,superAccess);
//Object o = get(pc,"_toNumeric",null);
if(member instanceof UDFPlus) {
UDFPlus udf = (UDFPlus)member;
if(udf.getReturnType()==CFTypes.TYPE_NUMERIC && udf.getFunctionArguments().length==0) {
try {
return Caster.toDoubleValue(_call(pc, KeyConstants.__toNumeric,udf, null, new Object[0]),defaultValue);
} catch (PageException e) {
return defaultValue;
}
}
}
}
return defaultValue;
}
@Override
public DateTime castToDateTime() throws PageException {
return castToDateTime(false);
}
@Override
public DateTime castToDateTime(DateTime defaultValue) {
return castToDateTime(false, defaultValue);
}
DateTime castToDateTime(boolean superAccess) throws PageException {
// magic function
PageContext pc = ThreadLocalPageContext.get();
if(pc!=null) {
Member member = getMember(pc,KeyConstants.__toDateTime,true,superAccess);
//Object o = get(pc,"_toDateTime",null);
if(member instanceof UDFPlus) {
UDFPlus udf = (UDFPlus)member;
if(udf.getReturnType()==CFTypes.TYPE_DATETIME && udf.getFunctionArguments().length==0) {
return Caster.toDate(_call(pc, KeyConstants.__toDateTime,udf, null, new Object[0]),pc.getTimeZone());
}
}
}
throw ExceptionUtil.addHint(new ExpressionException("Can't cast Component ["+getName()+"] to a date"),
"Add a User-Defined-Function to Component with the following pattern [_toDateTime():datetime] to cast it to a date");
}
DateTime castToDateTime(boolean superAccess,DateTime defaultValue) {
// magic function
PageContext pc = ThreadLocalPageContext.get();
if(pc!=null) {
Member member = getMember(pc,KeyConstants.__toDateTime,true,superAccess);
//Object o = get(pc,"_toDateTime",null);
if(member instanceof UDFPlus) {
UDFPlus udf = (UDFPlus)member;
if(udf.getReturnType()==CFTypes.TYPE_DATETIME && udf.getFunctionArguments().length==0) {
try {
return DateCaster.toDateAdvanced(_call(pc, KeyConstants.__toDateTime,udf, null, new Object[0]),true,pc.getTimeZone(),defaultValue);
} catch (PageException e) {
return defaultValue;
}
}
}
}
return defaultValue;
}
@Override
public synchronized Struct getMetaData(PageContext pc) throws PageException {
return getMetaData(ACCESS_PRIVATE,pc,top,false);
}
public synchronized Object getMetaStructItem(Collection.Key name) {
if(top.properties.meta!=null) {
return top.properties.meta.get(name,null);
}
return null;
}
protected static Struct getMetaData(int access,PageContext pc, ComponentImpl comp, boolean ignoreCache) throws PageException {
// Cache
Page page=MetadataUtil.getPageWhenMetaDataStillValid(pc, comp, ignoreCache);
if(page!=null && page.metaData!=null && page.metaData.get()!=null){
return page.metaData.get();
}
long creationTime=System.currentTimeMillis();
StructImpl sct=new StructImpl();
// fill udfs
metaUDFs(pc, comp, sct,access);
// meta
if(comp.properties.meta!=null)
StructUtil.copy(comp.properties.meta, sct, true);
String hint=comp.properties.hint;
String displayname=comp.properties.dspName;
if(!StringUtil.isEmpty(hint))sct.set(KeyConstants._hint,hint);
if(!StringUtil.isEmpty(displayname))sct.set(KeyConstants._displayname,displayname);
sct.set(KeyConstants._persistent,comp.properties.persistent);
sct.set(KeyConstants._hashCode,comp.hashCode());
sct.set(KeyConstants._accessors,comp.properties.accessors);
sct.set(KeyConstants._synchronized,comp.properties._synchronized);
if(comp.properties.output!=null)
sct.set(KeyConstants._output,comp.properties.output);
// extends
Struct ex=null;
if(comp.base!=null) ex=getMetaData(access,pc,comp.base,true);
if(ex!=null)sct.set(KeyConstants._extends,ex);
// implements
InterfaceCollection ic = comp.interfaceCollection;
if(ic!=null){
Set<String> set = ListUtil.listToSet(comp.properties.implement, ",",true);
InterfaceImpl[] interfaces = comp.interfaceCollection.getInterfaces();
if(!ArrayUtil.isEmpty(interfaces)){
Struct imp=new StructImpl();
for(int i=0;i<interfaces.length;i++){
if(!set.contains(interfaces[i].getCallPath())) continue;
//print.e("-"+interfaces[i].getCallPath());
imp.setEL(KeyImpl.init(interfaces[i].getCallPath()), interfaces[i].getMetaData(pc,true));
}
sct.set(KeyConstants._implements,imp);
}
}
// PageSource
PageSource ps = comp.pageSource;
sct.set(KeyConstants._fullname,ps.getComponentName());
sct.set(KeyConstants._name,ps.getComponentName());
sct.set(KeyConstants._path,ps.getDisplayPath());
sct.set(KeyConstants._type,"component");
Class<?> skeleton = comp.getJavaAccessClass(pc,new RefBooleanImpl(false),((ConfigImpl)pc.getConfig()).getExecutionLogEnabled(),false,false,((ConfigImpl)pc.getConfig()).getSupressWSBeforeArg());
if(skeleton !=null)sct.set(KeyConstants._skeleton, skeleton);
HttpServletRequest req = pc.getHttpServletRequest();
try {
String path=ContractPath.call(pc, ps.getDisplayPath()); // MUST better impl !!!
sct.set("remoteAddress",""+new URL(req.getScheme(),req.getServerName(),req.getServerPort(),req.getContextPath()+path+"?wsdl"));
} catch (Throwable t) {}
// Properties
if(comp.properties.properties!=null) {
ArrayImpl parr = new ArrayImpl();
Property p;
Iterator<Entry<String, Property>> pit = comp.properties.properties.entrySet().iterator();
while(pit.hasNext()){
p=pit.next().getValue();
parr.append(p.getMetaData());
}
parr.sort(new ArrayOfStructComparator(KeyConstants._name));
sct.set(KeyConstants._properties,parr);
}
page.metaData=new MetaDataSoftReference<Struct>(sct,creationTime);
return sct;
}
private static void metaUDFs(PageContext pc,ComponentImpl comp,Struct sct, int access) throws PageException {
ArrayImpl arr=new ArrayImpl();
//Collection.Key name;
Page page = ((PageSourceImpl)comp._getPageSource()).getPage();
if(page!=null && page.udfs!=null){
for(int i=0;i<page.udfs.length;i++){
if(page.udfs[i].getAccess()>access) continue;
arr.append(ComponentUtil.getMetaData(pc,(UDFPropertiesImpl) page.udfs[i]));
}
}
// property functions
Iterator<Entry<Key, UDF>> it = comp._udfs.entrySet().iterator();
Entry<Key, UDF> entry;
UDF udf;
while(it.hasNext()) {
entry= it.next();
udf=entry.getValue();
if(udf.getAccess()>access || !(udf instanceof UDFGSProperty)) continue;
if(comp.base!=null) {
if(udf==comp.base.getMember(access,entry.getKey(),true,true))
continue;
}
arr.append(udf.getMetaData(pc));
}
if(arr.size()!=0)sct.set(KeyConstants._functions,arr);
}
public boolean isInitalized() {
return isInit;
}
public void setInitalized(boolean isInit) {
this.isInit=isInit;;
}
/**
* sets a value to the current Component, dont to base Component
* @param key
* @param value
* @return value set
* @throws ExpressionException
*/
private synchronized Object _set(PageContext pc,Collection.Key key, Object value) throws ExpressionException {
if(value instanceof UDFPlus) {
UDFPlus udf = (UDFPlus)((UDFPlus)value).duplicate();
//udf.isComponentMember(true);///+++
udf.setOwnerComponent(this);
if(udf.getAccess()>Component.ACCESS_PUBLIC)
udf.setAccess(Component.ACCESS_PUBLIC);
_data.put(key,udf);
_udfs.put(key,udf);
hasInjectedFunctions=true;
}
else {
if(loaded && !isAccessible(ThreadLocalPageContext.get(pc), dataMemberDefaultAccess))
throw new ExpressionException("Component ["+getCallName()+"] has no accessible Member with name ["+key+"]","enable [trigger data member] in admininistrator to also invoke getters and setters");
_data.put(key,new DataMember(dataMemberDefaultAccess,value));
}
return value;
}
public void reg(Collection.Key key, UDFPlus udf) {
registerUDF(key, udf,useShadow,false);
}
public void reg(String key, UDFPlus udf) {
registerUDF(KeyImpl.init(key), udf,useShadow,false);
}
public void registerUDF(String key, UDF udf) {
registerUDF(KeyImpl.init(key), (UDFPlus) udf,useShadow,false);
}
public void registerUDF(String key, UDFProperties prop) {
registerUDF(KeyImpl.init(key), new UDFImpl( prop),useShadow,false);
}
public void registerUDF(Collection.Key key, UDF udf) {
registerUDF(key, (UDFPlus) udf,useShadow,false);
}
public void registerUDF(Collection.Key key, UDFProperties prop) {
registerUDF(key, new UDFImpl( prop),useShadow,false);
}
/*
* @deprecated injected is not used
*/
public void registerUDF(Collection.Key key, UDFPlus udf,boolean useShadow,boolean injected) {
udf.setOwnerComponent(this);//+++
_udfs.put(key,udf);
_data.put(key,udf);
if(useShadow)scope.setEL(key, udf);
}
@Override
public Object remove(Key key) throws PageException {
return _data.remove(key);
}
public Object removeEL(Collection.Key key) {
// MUST access muss beruecksichtigt werden
return _data.remove(key);
}
/*public Object set(PageContext pc, String name, Object value) throws PageException {
return set(pc, KeyImpl.init(name), value);
}*/
@Override
public Object set(PageContext pc, Collection.Key key, Object value) throws PageException {
if(pc==null)pc=ThreadLocalPageContext.get();
if(triggerDataMember(pc) && isInit) {
if(!isPrivate(pc)) {
return callSetter(pc, key, value);
}
}
return _set(pc,key,value);
}
@Override
public Object set(Collection.Key key, Object value) throws PageException {
return set(null,key,value);
}
/*public Object setEL(PageContext pc, String name, Object value) {
try {return set(pc, name, value);}
catch (PageException e) {return null;}
}*/
@Override
public Object setEL(PageContext pc, Collection.Key name, Object value) {
try {return set(pc, name, value);}
catch (PageException e) {return null;}
}
@Override
public Object setEL(Key key, Object value) {
return setEL(null, key, value);
}
@Override
public final Object put(Object key, Object value) {
// TODO find a better solution
// when a orm entity the data given by put or also written to the variables scope
if(entity) {
getComponentScope().put(key, value);
}
return super.put(key, value);
}
/*public Object get(PageContext pc, String name) throws PageException {
return get(pc, KeyImpl.init(name));
}*/
public Object get(PageContext pc, Collection.Key key) throws PageException {
Member member=getMember(pc,key,true,false);
if(member!=null) return member.getValue();
// trigger
if(triggerDataMember(pc) && !isPrivate(pc)) {
return callGetter(pc,key);
}
throw new ExpressionException("Component ["+getCallName()+"] has no accessible Member with name ["+key+"]","enable [trigger data member] in admininistrator to also invoke getters and setters");
//throw new ExpressionException("Component ["+getCallName()+"] has no accessible Member with name ["+name+"]");
}
private Object callGetter(PageContext pc,Collection.Key key) throws PageException {
Key getterName = KeyImpl.getInstance("get"+key.getLowerString());
Member member=getMember(pc,getterName,false,false);
if(member instanceof UDFPlus) {
UDFPlus udf = (UDFPlus)member;
if(udf.getFunctionArguments().length==0 && udf.getReturnType()!=CFTypes.TYPE_VOID) {
return _call(pc,getterName,udf,null,ArrayUtil.OBJECT_EMPTY);
}
}
throw new ExpressionException("Component ["+getCallName()+"] has no accessible Member with name ["+key+"]");
}
private Object callGetter(PageContext pc,Collection.Key key, Object defaultValue) {
Key getterName = KeyImpl.getInstance("get"+key.getLowerString());
Member member=getMember(pc,getterName,false,false);
if(member instanceof UDFPlus) {
UDFPlus udf = (UDFPlus)member;
if(udf.getFunctionArguments().length==0 && udf.getReturnType()!=CFTypes.TYPE_VOID) {
try {
return _call(pc,getterName,udf,null,ArrayUtil.OBJECT_EMPTY);
} catch (PageException e) {
return defaultValue;
}
}
}
return defaultValue;
}
private Object callSetter(PageContext pc,Collection.Key key, Object value) throws PageException {
Collection.Key setterName = KeyImpl.getInstance("set"+key.getLowerString());
Member member=getMember(pc,setterName,false,false);
if(member instanceof UDFPlus) {
UDFPlus udf = (UDFPlus)member;
if(udf.getFunctionArguments().length==1 && (udf.getReturnType()==CFTypes.TYPE_VOID) || udf.getReturnType()==CFTypes.TYPE_ANY ) {// TDOO support int return type
return _call(pc,setterName,udf,null,new Object[]{value});
}
}
return _set(pc,key,value);
}
/**
* return element that has at least given access or null
* @param access
* @param name
* @return matching value
* @throws PageException
*/
public Object get(int access, String name) throws PageException {
return get(access, KeyImpl.init(name));
}
public Object get(int access, Collection.Key key) throws PageException {
Member member=getMember(access,key,true,false);
if(member!=null) return member.getValue();
// Trigger
PageContext pc = ThreadLocalPageContext.get();
if(triggerDataMember(pc) && !isPrivate(pc)) {
return callGetter(pc,key);
}
throw new ExpressionException("Component ["+getCallName()+"] has no accessible Member with name ["+key+"]");
}
/*public Object get(PageContext pc, String name, Object defaultValue) {
return get(pc, KeyImpl.init(name), defaultValue);
}*/
@Override
public Object get(PageContext pc, Collection.Key key, Object defaultValue) {
Member member=getMember(pc,key,true,false);
if(member!=null) return member.getValue();
// trigger
if(triggerDataMember(pc) && !isPrivate(pc)) {
return callGetter(pc,key,defaultValue);
}
return defaultValue;
}
/**
* return element that has at least given access or null
* @param access
* @param name
* @return matching value
*/
protected Object get(int access, String name, Object defaultValue) {
return get(access, KeyImpl.init(name), defaultValue);
}
/**
* @param access
* @param key
* @param defaultValue
* @return
*/
public Object get(int access, Collection.Key key, Object defaultValue) {
Member member=getMember(access,key,true,false);
if(member!=null) return member.getValue();
// trigger
PageContext pc = ThreadLocalPageContext.get();
if(triggerDataMember(pc) && !isPrivate(pc)) {
return callGetter(pc,key,defaultValue);
}
return defaultValue;
}
@Override
public Object get(Collection.Key key) throws PageException {
return get(ThreadLocalPageContext.get(),key);
}
@Override
public Object get(Collection.Key key, Object defaultValue) {
return get(ThreadLocalPageContext.get(),key,defaultValue);
}
@Override
public Object call(PageContext pc, String name, Object[] args) throws PageException {
return _call(pc,KeyImpl.init(name),null,args,false);
}
public Object call(PageContext pc, Collection.Key name, Object[] args) throws PageException {
return _call(pc,name,null,args,false);
}
protected Object call(PageContext pc, int access, String name, Object[] args) throws PageException {
return _call(pc,access,KeyImpl.init(name),null,args,false);
}
public Object call(PageContext pc, int access, Collection.Key name, Object[] args) throws PageException {
return _call(pc,access,name,null,args,false);
}
@Override
public Object callWithNamedValues(PageContext pc, String name, Struct args) throws PageException {
return _call(pc,KeyImpl.init(name),args,null,false);
}
public Object callWithNamedValues(PageContext pc, Collection.Key methodName, Struct args) throws PageException {
return _call(pc,methodName,args,null,false);
}
protected Object callWithNamedValues(PageContext pc, int access, String name, Struct args) throws PageException {
return _call(pc,access,KeyImpl.init(name),args,null,false);
}
public Object callWithNamedValues(PageContext pc, int access, Collection.Key name, Struct args) throws PageException {
return _call(pc,access,name,args,null,false);
}
public boolean contains(PageContext pc,String name) {
return get(getAccess(pc),name,NullSupportHelper.NULL())!=NullSupportHelper.NULL();
}
/**
* @param pc
* @param key
* @return
*/
public boolean contains(PageContext pc,Key key) {
return get(getAccess(pc),key,NullSupportHelper.NULL())!=NullSupportHelper.NULL();
}
@Override
public boolean containsKey(Key key) {
return contains(ThreadLocalPageContext.get(),key);
}
public boolean contains(int access,String name) {
return get(access,name,NullSupportHelper.NULL())!=NullSupportHelper.NULL();
}
public boolean contains(int access,Key name) {
return get(access,name,NullSupportHelper.NULL())!=NullSupportHelper.NULL();
}
@Override
public Iterator<Collection.Key> keyIterator() {
return keyIterator(getAccess(ThreadLocalPageContext.get()));
}
@Override
public Iterator<String> keysAsStringIterator() {
return keysAsStringIterator(getAccess(ThreadLocalPageContext.get()));
}
@Override
public Iterator<Entry<Key, Object>> entryIterator() {
return entryIterator(getAccess(ThreadLocalPageContext.get()));
}
public Collection.Key[] keys() {
return keys(getAccess(ThreadLocalPageContext.get()));
}
@Override
public int size() {
return size(getAccess(ThreadLocalPageContext.get()));
}
@Override
public Class getJavaAccessClass(RefBoolean isNew) throws PageException {
return getJavaAccessClass(ThreadLocalPageContext.get(),isNew, false,true,true,true);
}
public Class getJavaAccessClass(PageContext pc,RefBoolean isNew) throws PageException {
return getJavaAccessClass(pc,isNew, false,true,true,true);
}
public Class getJavaAccessClass(PageContext pc,RefBoolean isNew,boolean writeLog, boolean takeTop, boolean create, boolean supressWSbeforeArg) throws PageException {
isNew.setValue(false);
ComponentProperties props =(takeTop)?top.properties:properties;
if(props.javaAccessClass==null) {
props.javaAccessClass=ComponentUtil.getComponentJavaAccess(pc,this,isNew,create,writeLog,supressWSbeforeArg);
}
return props.javaAccessClass;
}
public boolean isPersistent() {
return top.properties.persistent;
}
public boolean isAccessors() {
return top.properties.accessors;
}
public void setProperty(Property property) throws PageException {
top.properties.properties.put(StringUtil.toLowerCase(property.getName()),property);
if(top.properties.persistent || top.properties.accessors){
if(property.getDefault()!=null)scope.setEL(KeyImpl.init(property.getName()), property.getDefault());
PropertyFactory.createPropertyUDFs(this,property);
}
}
private void initProperties() throws PageException {
top.properties.properties=new LinkedHashMap<String,Property>();
// MappedSuperClass
if(isPersistent() && !isBasePeristent() && top.base!=null && top.base.properties.properties!=null && top.base.properties.meta!=null) {
boolean msc = Caster.toBooleanValue(top.base.properties.meta.get(KeyConstants._mappedSuperClass,Boolean.FALSE),false);
if(msc){
Property p;
Iterator<Entry<String, Property>> it = top.base.properties.properties.entrySet().iterator();
while(it.hasNext()) {
p = it.next().getValue();
if(p.isPeristent()) {
setProperty(p);
}
}
}
}
}
public Property[] getProperties(boolean onlyPeristent) {
return getProperties(onlyPeristent, false,false,false);
}
public Property[] getProperties(boolean onlyPeristent, boolean includeBaseProperties, boolean preferBaseProperties, boolean inheritedMappedSuperClassOnly) {
Map<String,Property> props=new LinkedHashMap<String,Property>();
_getProperties(top,props,onlyPeristent, includeBaseProperties, preferBaseProperties, inheritedMappedSuperClassOnly);
return props.values().toArray(new Property[props.size()]);
}
private static void _getProperties(ComponentImpl c,Map<String,Property> props,boolean onlyPeristent, boolean includeBaseProperties, boolean preferBaseProperties, boolean inheritedMappedSuperClassOnly) {
//if(c.properties.properties==null) return new Property[0];
// collect with filter
if(c.properties.properties!=null){
Property p;
Iterator<Entry<String, Property>> it = c.properties.properties.entrySet().iterator();
while(it.hasNext()) {
p = it.next().getValue();
if(!onlyPeristent || p.isPeristent()) {
if (!preferBaseProperties || !props.containsKey(p.getName().toLowerCase())) {
props.put(p.getName().toLowerCase(),p);
}
}
}
}
// MZ: Moved to the bottom to allow base properties to override inherited versions
if(includeBaseProperties && c.base!=null) {
if (!inheritedMappedSuperClassOnly || (c.base.properties.meta != null && Caster.toBooleanValue(c.base.properties.meta.get(KeyConstants._mappedSuperClass, Boolean.FALSE), false))) {
_getProperties(c.base, props, onlyPeristent, includeBaseProperties, preferBaseProperties, inheritedMappedSuperClassOnly);
}
}
}
public ComponentScope getComponentScope() {
return scope;
}
@Override
public int compareTo(boolean b) throws PageException {
return Operator.compare(castToBooleanValue(), b);
}
@Override
public int compareTo(DateTime dt) throws PageException {
return Operator.compare((Date)castToDateTime(), (Date)dt);
}
@Override
public int compareTo(double d) throws PageException {
return Operator.compare(castToDoubleValue(), d);
}
@Override
public int compareTo(String str) throws PageException {
return Operator.compare(castToString(), str);
}
public void addConstructorUDF(Key key, UDF value) {
if(constructorUDFs==null)
constructorUDFs=new HashMap<Key,UDF>();
constructorUDFs.put(key, value);
}
// MUST more native impl
public void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {
boolean pcCreated=false;
PageContext pc = ThreadLocalPageContext.get();
// MUST this is just a workaround
if(pc==null){
pcCreated=true;
ConfigWeb config = (ConfigWeb) ThreadLocalPageContext.getConfig();
Pair[] parr = new Pair[0];
pc=ThreadUtil.createPageContext(config, DevNullOutputStream.DEV_NULL_OUTPUT_STREAM, "localhost", "/","", new Cookie[0], parr, parr, new StructImpl());
}
// reading fails for serialized data from Railo version 4.1.2.002
String name = in.readUTF();
if(name.startsWith("evaluateComponent('") && name.endsWith("})")) {
readExternalOldStyle(pc, name);
return;
}
String md5 = in.readUTF();
Struct _this = Caster.toStruct(in.readObject(),null);
Struct _var = Caster.toStruct(in.readObject(),null);
try {
ComponentImpl other=(ComponentImpl)EvaluateComponent.invoke(pc, name, md5, _this,_var);
_readExternal(other);
}
catch (PageException e) {
throw ExceptionUtil.toIOException(e);
}
finally {
if(pcCreated)ThreadLocalPageContext.release();
}
}
private void readExternalOldStyle(PageContext pc, String str) throws IOException {
try {
ComponentImpl other=(ComponentImpl) new CFMLExpressionInterpreter().interpret(pc,str);
_readExternal(other);
}
catch (PageException e) {
throw ExceptionUtil.toIOException(e);
}
}
private void _readExternal(ComponentImpl other) {
this._data=other._data;
this._udfs=other._udfs;
setOwner(_udfs);
setOwner(_data);
this.afterConstructor=other.afterConstructor;
this.base=other.base;
//this.componentPage=other.componentPage;
this.pageSource=other.pageSource;
this.constructorUDFs=other.constructorUDFs;
this.dataMemberDefaultAccess=other.dataMemberDefaultAccess;
this.interfaceCollection=other.interfaceCollection;
this.isInit=other.isInit;
this.properties=other.properties;
this.scope=other.scope;
this.top=this;
this._triggerDataMember=other._triggerDataMember;
this.hasInjectedFunctions=other.hasInjectedFunctions;
this.useShadow=other.useShadow;
this.entity=other.entity;
}
private void setOwner(Map<Key,? extends Member> data) {
Member m;
Iterator<? extends Member> it = data.values().iterator();
while(it.hasNext()){
m=it.next();
if(m instanceof UDFPlus) {
((UDFPlus)m).setOwnerComponent(this);
}
}
}
public void writeExternal(ObjectOutput out) throws IOException {
ComponentWrap cw = new ComponentWrap(Component.ACCESS_PRIVATE,this);
Struct _this=new StructImpl();
Struct _var=new StructImpl();
// this scope (removing all UDFs)
Object member;
{
Iterator<Entry<Key, Object>> it = cw.entryIterator();
Entry<Key, Object> e;
while(it.hasNext()) {
e = it.next();
member = e.getValue();
if(member instanceof UDF)continue;
_this.setEL(e.getKey(), member);
}
}
// variables scope (removing all UDFs and key "this")
{
ComponentScope scope = getComponentScope();
Iterator<Entry<Key, Object>> it = scope.entryIterator();
Entry<Key, Object> e;
Key k;
while(it.hasNext()) {
e = it.next();
k = e.getKey();
if(KeyConstants._THIS.equalsIgnoreCase(k))continue;
member = e.getValue();
if(member instanceof UDF)continue;
_var.setEL(e.getKey(), member);
}
}
out.writeUTF(getAbsName());
out.writeUTF(ComponentUtil.md5(cw));
out.writeObject(_this);
out.writeObject(_var);
}
@Override
public ComponentAccess _base() {
return base;
}
public InterfaceCollection _interfaceCollection() {
return interfaceCollection;
}
private boolean triggerDataMember(PageContext pc) {
if(_triggerDataMember!=null) return _triggerDataMember.booleanValue();
if(pc==null || pc.getApplicationContext()==null){
//print.ds(""+(pc==null));// TODO why this is true sometimes?
return false;
}
return pc.getApplicationContext().getTriggerComponentDataMember();
}
public void setLoaded(boolean loaded) {
this.loaded=loaded;
}
public boolean hasInjectedFunctions() {
return hasInjectedFunctions;
}
@Override
public void setEntity(boolean entity) {
this.entity=entity;
}
@Override
public boolean isEntity() {
return entity;
}
}