package railo.runtime; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import railo.commons.io.CharsetUtil; import railo.commons.io.IOUtil; import railo.commons.io.res.Resource; import railo.commons.io.res.util.ResourceUtil; import railo.commons.lang.CFTypes; import railo.commons.lang.ExceptionUtil; import railo.commons.lang.StringUtil; import railo.commons.lang.mimetype.MimeType; import railo.runtime.config.ConfigImpl; import railo.runtime.config.ConfigWebImpl; import railo.runtime.converter.BinaryConverter; import railo.runtime.converter.ConverterException; import railo.runtime.converter.JSONConverter; import railo.runtime.converter.JavaConverter; import railo.runtime.converter.ScriptConverter; import railo.runtime.converter.WDDXConverter; import railo.runtime.converter.XMLConverter; import railo.runtime.converter.bin.ImageConverter; import railo.runtime.dump.DumpUtil; import railo.runtime.dump.DumpWriter; import railo.runtime.exp.ApplicationException; import railo.runtime.exp.ExpressionException; import railo.runtime.exp.PageException; import railo.runtime.gateway.GatewayEngineImpl; import railo.runtime.interpreter.CFMLExpressionInterpreter; import railo.runtime.interpreter.JSONExpressionInterpreter; import railo.runtime.net.http.ReqRspUtil; import railo.runtime.net.rpc.server.ComponentController; import railo.runtime.net.rpc.server.RPCServer; import railo.runtime.op.Caster; import railo.runtime.op.Constants; import railo.runtime.op.Decision; import railo.runtime.rest.RestUtil; import railo.runtime.rest.Result; import railo.runtime.rest.path.Path; import railo.runtime.type.Array; import railo.runtime.type.ArrayImpl; import railo.runtime.type.Collection; import railo.runtime.type.Collection.Key; import railo.runtime.type.FunctionArgument; import railo.runtime.type.KeyImpl; import railo.runtime.type.Struct; import railo.runtime.type.StructImpl; import railo.runtime.type.UDF; import railo.runtime.type.UDFPlus; import railo.runtime.type.cfc.ComponentAccess; import railo.runtime.type.scope.Scope; import railo.runtime.type.util.ArrayUtil; import railo.runtime.type.util.CollectionUtil; import railo.runtime.type.util.ComponentUtil; import railo.runtime.type.util.KeyConstants; import railo.runtime.type.util.ListUtil; import railo.runtime.type.util.StructUtil; import railo.runtime.type.util.UDFUtil; /** * A Page that can produce Components */ public abstract class ComponentPage extends PagePlus { public static final Collection.Key ACCEPT_ARG_COLL_FORMATS = KeyImpl.getInstance("acceptedArgumentCollectionFormats"); private static final long serialVersionUID = -3483642653131058030L; public static final railo.runtime.type.Collection.Key REMOTE_PERSISTENT_ID = KeyImpl.intern("Id16hohohh"); private long lastCheck=-1; public abstract ComponentImpl newInstance(PageContext pc,String callPath,boolean isRealPath) throws railo.runtime.exp.PageException; @Override public void call(PageContext pc) throws PageException { // remote persistent (only type server is supported) String strRemotePersisId = Caster.toString(getURLorForm(pc,REMOTE_PERSISTENT_ID,null),null);//Caster.toString(pc.urlFormScope().get(REMOTE_PERSISTENT_ID,null),null); if(!StringUtil.isEmpty(strRemotePersisId,true)) { strRemotePersisId=strRemotePersisId.trim(); } else strRemotePersisId=null; HttpServletRequest req = pc.getHttpServletRequest(); // client String client = Caster.toString(req.getAttribute("client"),null); // call type (invocation, store-only) String callType = Caster.toString(req.getAttribute("call-type"),null); boolean fromGateway="railo-gateway-1-0".equals(client); boolean fromRest="railo-rest-1-0".equals(client); Component component; try { pc.setSilent(); // load the cfc try { if(fromGateway && strRemotePersisId!=null) { ConfigWebImpl config=(ConfigWebImpl) pc.getConfig(); GatewayEngineImpl engine = config.getGatewayEngine(); component=engine.getPersistentRemoteCFC(strRemotePersisId); if(component==null) { component=newInstance(pc,getPageSource().getComponentName(),false); if(!fromGateway)component=ComponentWrap.toComponentWrap(Component.ACCESS_REMOTE,component); engine.setPersistentRemoteCFC(strRemotePersisId,component); } } else { component=newInstance(pc,getPageSource().getComponentName(),false); if(!fromGateway)component=ComponentWrap.toComponentWrap(Component.ACCESS_REMOTE,component); } } finally { pc.unsetSilent(); } // Only get the Component, no invocation if("store-only".equals(callType)) { req.setAttribute("component", component); return; } // METHOD INVOCATION String qs=ReqRspUtil.getQueryString(pc.getHttpServletRequest()); if(pc.getBasePageSource()==this.getPageSource() && pc.getConfig().debug()) pc.getDebugger().setOutput(false); boolean isPost=pc.getHttpServletRequest().getMethod().equalsIgnoreCase("POST"); boolean suppressContent = ((ConfigImpl)pc.getConfig()).isSuppressContent(); if(suppressContent)pc.clear(); Object method; if(fromRest){ callRest(pc,component,Caster.toString(req.getAttribute("rest-path"),""),(Result)req.getAttribute("rest-result"),suppressContent); return; } // POST if(isPost) { // Soap if(isSoap(pc)) { callWebservice(pc,component); //close(pc); return; } // WDDX else if((method=getURLorForm(pc, KeyConstants._method, null))!=null) { callWDDX(pc,component,KeyImpl.toKey(method),suppressContent); //close(pc); return; } } // GET else { // WSDL if(qs!=null && qs.trim().equalsIgnoreCase("wsdl")) { callWSDL(pc,component); //close(pc); return; } // WDDX else if((method=getURLorForm(pc, KeyConstants._method, null))!=null) { callWDDX(pc,component,KeyImpl.toKey(method),suppressContent); //close(pc); return; } if(qs!=null) { int rf = UDFUtil.toReturnFormat(qs.trim(),-1); if(rf!=-1) callCFCMetaData(pc,component,rf); //close(pc); return; } } // Include MUST Array path = pc.getTemplatePath(); //if(path.size()>1 ) { if(path.size()>1 && !(path.size()==3 && ListUtil.last(path.getE(2).toString(),"/\\",true).equalsIgnoreCase(railo.runtime.config.Constants.APP_CFC)) ) {// MUSTMUST bad impl -> check with and without application.cfc ComponentWrap c = ComponentWrap.toComponentWrap(Component.ACCESS_PRIVATE,ComponentUtil.toComponentAccess(component)); Key[] keys = c.keys(); Object el; Scope var = pc.variablesScope(); for(int i=0;i<keys.length;i++) { el=c.get(keys[i],null); if(el instanceof UDF) var.set(keys[i], el); } return; } // DUMP //TODO component.setAccess(pc,Component.ACCESS_PUBLIC); String cdf = pc.getConfig().getComponentDumpTemplate(); if(cdf!=null && cdf.trim().length()>0) { pc.variablesScope().set(KeyConstants._component,component); pc.doInclude(cdf); } else pc.write(pc.getConfig().getDefaultDumpWriter(DumpWriter.DEFAULT_RICH).toString(pc,component.toDumpData(pc,9999,DumpUtil.toDumpProperties() ),true)); } catch(Throwable t) { throw Caster.toPageException(t);//Exception Handler.castAnd Stack(t, this, pc); } } private Object getURLorForm(PageContext pc, Key key, Object defaultValue) { Object res = pc.formScope().get(key,null); if(res!=null) return res; return pc.urlScope().get(key,defaultValue); } private void callRest(PageContext pc, Component component, String path, Result result, boolean suppressContent) throws IOException, ConverterException { String method = pc.getHttpServletRequest().getMethod(); String[] subPath = result.getPath(); Struct cMeta; try { cMeta = component.getMetaData(pc); } catch (PageException pe) { throw ExceptionUtil.toIOException(pe); } // Consumes MimeType[] cConsumes=null; String strMimeType = Caster.toString(cMeta.get(KeyConstants._consumes,null),null); if(!StringUtil.isEmpty(strMimeType,true)){ cConsumes = MimeType.getInstances(strMimeType,','); } // Produces MimeType[] cProduces=null; strMimeType = Caster.toString(cMeta.get(KeyConstants._produces,null),null); if(!StringUtil.isEmpty(strMimeType,true)){ cProduces = MimeType.getInstances(strMimeType,','); } Iterator<Entry<Key, Object>> it = component.entryIterator(); Entry<Key, Object> e; Object value; UDF udf; Struct meta; int status=404; MimeType bestP,bestC; while(it.hasNext()){ e = it.next(); value=e.getValue(); if(value instanceof UDF){ udf=(UDF)value; try { meta = udf.getMetaData(pc); // check if http method match String httpMethod = Caster.toString(meta.get(KeyConstants._httpmethod,null),null); if(StringUtil.isEmpty(httpMethod) || !httpMethod.equalsIgnoreCase(method)) continue; // get consumes mimetype MimeType[] consumes; strMimeType = Caster.toString(meta.get(KeyConstants._consumes,null),null); if(!StringUtil.isEmpty(strMimeType,true)){ consumes = MimeType.getInstances(strMimeType,','); } else consumes=cConsumes; // get produces mimetype MimeType[] produces; strMimeType = Caster.toString(meta.get(KeyConstants._produces,null),null); if(!StringUtil.isEmpty(strMimeType,true)){ produces = MimeType.getInstances(strMimeType,','); } else produces=cProduces; String restPath = Caster.toString(meta.get(KeyConstants._restPath,null),null); // no rest path if(StringUtil.isEmpty(restPath)){ if(ArrayUtil.isEmpty(subPath)) { bestC = best(consumes,result.getContentType()); bestP = best(produces,result.getAccept()); if(bestC==null) status=405; else if(bestP==null) status=406; else { status=200; _callRest(pc, component, udf, path, result.getVariables(),result,bestP,produces, suppressContent,e.getKey()); break; } } } else { Struct var = result.getVariables(); int index=RestUtil.matchPath(var, Path.init(restPath)/*TODO cache this*/, result.getPath()); if(index>=0 && index+1==result.getPath().length) { bestC = best(consumes,result.getContentType()); bestP = best(produces,result.getAccept()); if(bestC==null) status=405; else if(bestP==null) status=406; else { status=200; _callRest(pc, component, udf, path, var,result,bestP,produces, suppressContent,e.getKey()); break; } } } } catch (PageException pe) {} } } if(status==404) RestUtil.setStatus(pc,404,"no rest service for ["+path+"] found"); else if(status==405) RestUtil.setStatus(pc,405,"Unsupported Media Type"); else if(status==406) RestUtil.setStatus(pc,406,"Not Acceptable"); } private MimeType best(MimeType[] produces, MimeType... accept) { if(ArrayUtil.isEmpty(produces)){ if(accept.length>0) return accept[0]; return MimeType.ALL; } MimeType best=null,tmp; for(int a=0;a<accept.length;a++){ tmp=accept[a].bestMatch(produces); if(tmp!=null && !accept[a].hasWildCards() && tmp.hasWildCards()){ tmp=accept[a]; } if(tmp!=null && (best==null || best.getQuality()<tmp.getQuality() || (best.getQuality()==tmp.getQuality() && best.hasWildCards() && !tmp.hasWildCards()))) best=tmp; } return best; } private void _callRest(PageContext pc, Component component, UDF udf,String path, Struct variables, Result result, MimeType best,MimeType[] produces, boolean suppressContent, Key methodName) throws PageException, IOException, ConverterException { FunctionArgument[] fa=udf.getFunctionArguments(); Struct args=new StructImpl(),meta; Key name; String restArgName,restArgSource,value; for(int i=0;i<fa.length;i++){ name = fa[i].getName(); meta=fa[i].getMetaData(); restArgSource=meta==null?"":Caster.toString(meta.get(KeyConstants._restArgSource,""),""); if("path".equalsIgnoreCase(restArgSource)) setValue(fa[i],args,name, variables.get(name,null)); if("query".equalsIgnoreCase(restArgSource) || "url".equalsIgnoreCase(restArgSource)) setValue(fa[i],args,name, pc.urlScope().get(name,null)); if("form".equalsIgnoreCase(restArgSource)) setValue(fa[i],args,name, pc.formScope().get(name,null)); if("cookie".equalsIgnoreCase(restArgSource)) setValue(fa[i],args,name, pc.cookieScope().get(name,null)); if("header".equalsIgnoreCase(restArgSource) || "head".equalsIgnoreCase(restArgSource)) { restArgName=meta==null?"":Caster.toString(meta.get(KeyConstants._restArgName,""),""); if(StringUtil.isEmpty(restArgName))restArgName=name.getString(); value=ReqRspUtil.getHeaderIgnoreCase(pc, restArgName, null); setValue(fa[i],args,name,value); } if("matrix".equalsIgnoreCase(restArgSource)) setValue(fa[i],args,name, result.getMatrix().get(name,null)); if("body".equalsIgnoreCase(restArgSource) || StringUtil.isEmpty(restArgSource,true)){ boolean isSimple=CFTypes.isSimpleType(fa[i].getType()); Object body = ReqRspUtil.getRequestBody(pc,true,null); if(isSimple && !Decision.isSimpleValue(body)) body= ReqRspUtil.getRequestBody(pc,false,null); setValue(fa[i],args,name, body); } } Object rtn=null; try{ if(suppressContent)pc.setSilent(); rtn = component.callWithNamedValues(pc, methodName, args); } catch (PageException e) { RestUtil.setStatus(pc, 500, ExceptionUtil.getMessage(e)); } finally { if(suppressContent)pc.unsetSilent(); } // custom response Struct sct = result.getCustomResponse(); boolean hasContent=false; if(sct!=null){ HttpServletResponse rsp = pc.getHttpServletResponse(); // status int status = Caster.toIntValue(sct.get(KeyConstants._status,Constants.DOUBLE_ZERO),0); if(status>0)rsp.setStatus(status); // content Object o=sct.get(KeyConstants._content,null); if(o!=null) { String content=Caster.toString(o,null); if(content!=null) { try { pc.forceWrite(content); hasContent=true; } catch (IOException e) {} } } // headers Struct headers=Caster.toStruct(sct.get(KeyConstants._headers,null),null); if(headers!=null){ //Key[] keys = headers.keys(); Iterator<Entry<Key, Object>> it = headers.entryIterator(); Entry<Key, Object> e; String n,v; Object tmp; while(it.hasNext()){ e = it.next(); n=e.getKey().getString(); tmp=e.getValue(); v=Caster.toString(tmp,null); if(tmp!=null && v==null) v=tmp.toString(); rsp.setHeader(n, v); } } } // convert result if(rtn!=null && !hasContent){ Props props = new Props(); props.format=result.getFormat(); Charset cs = getCharset(pc); if(result.hasFormatExtension()){ //setFormat(pc.getHttpServletResponse(), props.format,cs); _writeOut(pc, props, null, rtn,cs); } else { if(best!=null && !MimeType.ALL.same(best)) { int f = MimeType.toFormat(best, -1); if(f!=-1) { props.format=f; //setFormat(pc.getHttpServletResponse(), f,cs); _writeOut(pc, props, null, rtn,cs); } else { writeOut(pc,props,rtn,best); } } else { _writeOut(pc, props, null, rtn,cs); } } } } private void setValue(FunctionArgument fa, Struct args, Key name, Object value) { if(value==null){ Struct meta = fa.getMetaData(); if(meta!=null)value=meta.get(KeyConstants._default,null); } args.setEL(name, value); } private void writeOut(PageContext pc, Props props, Object obj, MimeType mt) throws PageException, IOException, ConverterException { // TODO miemtype mapping with converter defintion from external file // Images if(mt.same(MimeType.IMAGE_GIF)) writeOut(pc,obj,mt,new ImageConverter("gif")); else if(mt.same(MimeType.IMAGE_JPG)) writeOut(pc,obj,mt,new ImageConverter("jpeg")); else if(mt.same(MimeType.IMAGE_PNG)) writeOut(pc,obj,mt,new ImageConverter("png")); else if(mt.same(MimeType.IMAGE_TIFF)) writeOut(pc,obj,mt,new ImageConverter("tiff")); else if(mt.same(MimeType.IMAGE_BMP)) writeOut(pc,obj,mt,new ImageConverter("bmp")); else if(mt.same(MimeType.IMAGE_WBMP)) writeOut(pc,obj,mt,new ImageConverter("wbmp")); else if(mt.same(MimeType.IMAGE_FBX)) writeOut(pc,obj,mt,new ImageConverter("fbx")); else if(mt.same(MimeType.IMAGE_FBX)) writeOut(pc,obj,mt,new ImageConverter("fbx")); else if(mt.same(MimeType.IMAGE_PNM)) writeOut(pc,obj,mt,new ImageConverter("pnm")); else if(mt.same(MimeType.IMAGE_PGM)) writeOut(pc,obj,mt,new ImageConverter("pgm")); else if(mt.same(MimeType.IMAGE_PBM)) writeOut(pc,obj,mt,new ImageConverter("pbm")); else if(mt.same(MimeType.IMAGE_ICO)) writeOut(pc,obj,mt,new ImageConverter("ico")); else if(mt.same(MimeType.IMAGE_PSD)) writeOut(pc,obj,mt,new ImageConverter("psd")); else if(mt.same(MimeType.IMAGE_ASTERIX)) writeOut(pc,obj,MimeType.IMAGE_PNG,new ImageConverter("png")); // Application else if(mt.same(MimeType.APPLICATION_JAVA)) writeOut(pc,obj,mt,new JavaConverter()); //if("application".equalsIgnoreCase(mt.getType())) else _writeOut(pc, props, null, obj,null); } private static void writeOut(PageContext pc, Object obj, MimeType mt,BinaryConverter converter) throws ConverterException, IOException { pc.getResponse().setContentType(mt.toString()); OutputStream os=null; try{ converter.writeOut(pc, obj, os=pc.getResponseStream()); } finally{ IOUtil.closeEL(os); } } public static boolean isSoap(PageContext pc) { HttpServletRequest req = pc.getHttpServletRequest(); InputStream is=null; try { is=req.getInputStream(); String input = IOUtil.toString(is,CharsetUtil.ISO88591); return StringUtil.indexOfIgnoreCase(input, "soap:Envelope")!=-1 || StringUtil.indexOfIgnoreCase(input, "soapenv:Envelope")!=-1 || StringUtil.indexOfIgnoreCase(input, "SOAP-ENV:Envelope")!=-1; } catch (IOException e) { return false; } finally { IOUtil.closeEL(is); } } private void callWDDX(PageContext pc, Component component, Collection.Key methodName, boolean suppressContent) throws IOException, ConverterException, PageException { //Struct url = StructUtil.duplicate(pc.urlFormScope(),true); Struct url=StructUtil.merge(new Struct[]{pc.formScope(),pc.urlScope()}); // define args url.removeEL(KeyConstants._fieldnames); url.removeEL(KeyConstants._method); Object args=url.get(KeyConstants._argumentCollection,null); String strArgCollFormat=Caster.toString(url.get("argumentCollectionFormat",null),null); // url.returnFormat int urlReturnFormat=-1; Object oReturnFormatFromURL=url.get(KeyConstants._returnFormat,null); if(oReturnFormatFromURL!=null)urlReturnFormat=UDFUtil.toReturnFormat(Caster.toString(oReturnFormatFromURL,null),-1); // request header "accept" List<MimeType> accept = ReqRspUtil.getAccept(pc); int headerReturnFormat = MimeType.toFormat(accept,UDF.RETURN_FORMAT_XML, -1); Object queryFormat=url.get(KeyConstants._queryFormat,null); if(args==null){ args=pc.getHttpServletRequest().getAttribute("argumentCollection"); } if(StringUtil.isEmpty(strArgCollFormat)) { strArgCollFormat=Caster.toString(pc.getHttpServletRequest().getAttribute("argumentCollectionFormat"),null); } //content-type Charset cs = getCharset(pc); Object o = component.get(pc,methodName,null); Props props = getProps(pc, o, urlReturnFormat,headerReturnFormat); if(!props.output) setFormat(pc.getHttpServletResponse(),props.format,cs); Object rtn=null; try{ if(suppressContent)pc.setSilent(); if(args==null){ url=translate(component,methodName.getString(),url); rtn = component.callWithNamedValues(pc, methodName, url); } else if(args instanceof String){ String str=(String)args; int format = UDFUtil.toReturnFormat(strArgCollFormat,-1); // CFML if(UDF.RETURN_FORMAT_SERIALIZE==format) { // do not catch exception when format is defined args=new CFMLExpressionInterpreter().interpret(pc, str); } // JSON if(UDF.RETURN_FORMAT_JSON==format) { // do not catch exception when format is defined args=new JSONExpressionInterpreter(false).interpret(pc, str); } // default else { // catch exception when format is not defined, then in this case the string can also be a simple argument try { args=new JSONExpressionInterpreter(false).interpret(pc, str); } catch (PageException pe) { try { args=new CFMLExpressionInterpreter().interpret(pc, str); } catch (PageException _pe) {} } } } // call if(args!=null) { if(Decision.isCastableToStruct(args)){ rtn = component.callWithNamedValues(pc, methodName, Caster.toStruct(args,false)); } else if(Decision.isCastableToArray(args)){ rtn = component.call(pc, methodName, Caster.toNativeArray(args)); } else { Object[] ac=new Object[1]; ac[0]=args; rtn = component.call(pc, methodName, ac); } } } finally { if(suppressContent)pc.unsetSilent(); } // convert result if(rtn!=null){ if(pc.getHttpServletRequest().getHeader("AMF-Forward")!=null) { pc.variablesScope().setEL("AMF-Forward", rtn); } else { _writeOut(pc, props, queryFormat, rtn,cs); } } } private static void setFormat(HttpServletResponse rsp, int format, Charset charset) { String strCS; if(charset==null) strCS=""; else strCS="; charset="+charset.displayName(); switch(format){ case UDF.RETURN_FORMAT_WDDX: rsp.setContentType("text/xml"+strCS); rsp.setHeader("Return-Format", "wddx"); break; case UDF.RETURN_FORMAT_JSON: rsp.setContentType("application/json"+strCS); rsp.setHeader("Return-Format", "json"); break; case UDF.RETURN_FORMAT_PLAIN: rsp.setContentType("text/plain"+strCS); rsp.setHeader("Return-Format", "plain"); break; case UDF.RETURN_FORMAT_XML: rsp.setContentType("text/xml"+strCS); rsp.setHeader("Return-Format", "xml"); break; case UDF.RETURN_FORMAT_SERIALIZE: rsp.setContentType("application/cfml"+strCS); rsp.setHeader("Return-Format", "cfml"); break; case UDFPlus.RETURN_FORMAT_JAVA: rsp.setContentType("application/java"); // no charset this is a binary format rsp.setHeader("Return-Format", "java"); break; } } private static Props getProps(PageContext pc, Object o,int urlReturnFormat,int headerReturnFormat) { Props props = new Props(); props.strType="any"; props.secureJson=pc.getApplicationContext().getSecureJson(); int udfReturnFormat=-1; if(o instanceof UDFPlus) { UDFPlus udf = ((UDFPlus)o); udfReturnFormat=udf.getReturnFormat(-1); props.type=udf.getReturnType(); props.strType=udf.getReturnTypeAsString(); props.output=udf.getOutput(); if(udf.getSecureJson()!=null)props.secureJson=udf.getSecureJson().booleanValue(); } // format if(isValid(urlReturnFormat)) props.format=urlReturnFormat; else if(isValid(udfReturnFormat)) props.format=udfReturnFormat; else if(isValid(headerReturnFormat)) props.format=headerReturnFormat; else props.format=UDF.RETURN_FORMAT_WDDX; // return type XML ignore WDDX if(props.type==CFTypes.TYPE_XML) { if(UDF.RETURN_FORMAT_WDDX==props.format) props.format=UDF.RETURN_FORMAT_PLAIN; } return props; } private static boolean isValid(int returnFormat) { return returnFormat!=-1 && returnFormat!=UDF.RETURN_FORMAT_XML; } public static void writeToResponseStream(PageContext pc,Component component, String methodName,int urlReturnFormat,int headerReturnFormat,Object queryFormat,Object rtn) throws ConverterException, PageException, IOException { Object o = component.get(KeyImpl.init(methodName),null); Props p = getProps(pc, o, urlReturnFormat,headerReturnFormat); _writeOut(pc, p, queryFormat, rtn,null); } private static void _writeOut(PageContext pc,Props props,Object queryFormat,Object rtn,Charset cs) throws ConverterException, PageException, IOException { // return type XML ignore WDDX if(props.type==CFTypes.TYPE_XML) { //if(UDF.RETURN_FORMAT_WDDX==format) format=UDF.RETURN_FORMAT_PLAIN; rtn=Caster.toString(Caster.toXML(rtn)); } // function does no real cast, only check it else rtn=Caster.castTo(pc, (short)props.type, props.strType, rtn); setFormat(pc.getHttpServletResponse(), props.format, cs); // WDDX if(UDF.RETURN_FORMAT_WDDX==props.format) { WDDXConverter converter = new WDDXConverter(pc.getTimeZone(),false,false); converter.setTimeZone(pc.getTimeZone()); pc.forceWrite(converter.serialize(rtn)); } // JSON else if(UDF.RETURN_FORMAT_JSON==props.format) { boolean byColumn = false; if(queryFormat instanceof String){ String strQF=((String) queryFormat).trim(); if(strQF.equalsIgnoreCase("row")); else if(strQF.equalsIgnoreCase("column"))byColumn=true; else throw new ApplicationException("invalid queryformat definition ["+strQF+"], valid formats are [row,column]"); } JSONConverter converter = new JSONConverter(false); String prefix=""; if(props.secureJson) { prefix=pc.getApplicationContext().getSecureJsonPrefix(); if(prefix==null)prefix=""; } pc.forceWrite(prefix+converter.serialize(pc,rtn,byColumn)); } // CFML else if(UDF.RETURN_FORMAT_SERIALIZE==props.format) { ScriptConverter converter = new ScriptConverter(false); pc.forceWrite(converter.serialize(rtn)); } // XML else if(UDF.RETURN_FORMAT_XML==props.format) { XMLConverter converter = new XMLConverter(pc.getTimeZone(),false); converter.setTimeZone(pc.getTimeZone()); pc.forceWrite(converter.serialize(rtn)); } // Plain else if(UDF.RETURN_FORMAT_PLAIN==props.format) { pc.forceWrite(Caster.toString(rtn)); } // JAVA else if(UDFPlus.RETURN_FORMAT_JAVA==props.format) { writeOut(pc,rtn,MimeType.APPLICATION_JAVA,new JavaConverter()); } else throw new IOException("invalid return format defintion:"+props.format); } public static Struct translate(Component c, String strMethodName, Struct params) { Collection.Key methodName=KeyImpl.init(strMethodName); Key[] keys = CollectionUtil.keys(params); FunctionArgument[] args=null; int index=-1; Object value; for(int i=0;i<keys.length;i++){ index=Caster.toIntValue(keys[i].getString(),0); if(index>0) { if(args==null)args=_getArgs(c,methodName); if(args!=null && index<=args.length) { value=params.removeEL(keys[i]); if(value!=null)params.setEL(args[index-1].getName(), value); } } } return params; } private static FunctionArgument[] _getArgs(Component c, Collection.Key methodName) { Object o=c.get(methodName,null); if(o instanceof UDF) return ((UDF) o).getFunctionArguments(); return null; } private void callCFCMetaData(PageContext pc, Component cfc, int format) throws IOException, PageException, ConverterException { ComponentAccess ca = ComponentUtil.toComponentAccess(cfc); ComponentWrap cw = new ComponentWrap(Component.ACCESS_REMOTE,ca); ComponentScope scope = cw.getComponentScope(); Struct udfs=new StructImpl(),sctUDF,sctArg; Array arrArg; Iterator<Object> it = scope.valueIterator(); Object v; UDF udf; FunctionArgument[] args; while(it.hasNext()){ v=it.next(); // UDF if(v instanceof UDF) { udf=(UDF) v; sctUDF=new StructImpl(); arrArg=new ArrayImpl(); udfs.setEL(udf.getFunctionName(), sctUDF); args = udf.getFunctionArguments(); for(int i=0;i<args.length;i++){ sctArg=new StructImpl(); arrArg.appendEL(sctArg); sctArg.setEL(KeyConstants._name, args[i].getName().getString()); sctArg.setEL(KeyConstants._type, args[i].getTypeAsString()); sctArg.setEL(KeyConstants._required, args[i].isRequired()); if(!StringUtil.isEmpty(args[i].getHint()))sctArg.setEL(KeyConstants._hint, args[i].getHint()); } sctUDF.set(KeyConstants._arguments, arrArg); sctUDF.set(KeyConstants._returntype, udf.getReturnTypeAsString()); } } Struct rtn=new StructImpl(); rtn.set(KeyConstants._functions, udfs); rtn.set(ACCEPT_ARG_COLL_FORMATS, "cfml,json"); InputStream is; Charset cs=null; // WDDX if(UDF.RETURN_FORMAT_WDDX==format) { WDDXConverter converter = new WDDXConverter(pc.getTimeZone(),false,false); converter.setTimeZone(pc.getTimeZone()); String str = converter.serialize(rtn); cs = getCharset(pc); is = new ByteArrayInputStream(str.getBytes(cs)); } // JSON else if(UDF.RETURN_FORMAT_JSON==format) { boolean byColumn = false; JSONConverter converter = new JSONConverter(false); String str = converter.serialize(pc,rtn,byColumn); cs = getCharset(pc); is = new ByteArrayInputStream(str.getBytes(cs)); } // CFML else if(UDF.RETURN_FORMAT_SERIALIZE==format) { ScriptConverter converter = new ScriptConverter(false); String str=converter.serialize(rtn); cs = getCharset(pc); is = new ByteArrayInputStream(str.getBytes(cs)); } // XML else if(UDF.RETURN_FORMAT_XML==format) { XMLConverter converter = new XMLConverter(pc.getTimeZone(),false); converter.setTimeZone(pc.getTimeZone()); String str=converter.serialize(rtn); cs = getCharset(pc); is = new ByteArrayInputStream(str.getBytes(cs)); } // Plain else if(UDF.RETURN_FORMAT_PLAIN==format) { String str= Caster.toString(rtn); cs = getCharset(pc); is = new ByteArrayInputStream(str.getBytes(cs)); } // Java else if(UDFPlus.RETURN_FORMAT_JAVA==format) { byte[] bytes = JavaConverter.serializeAsBinary(rtn); is = new ByteArrayInputStream(bytes); } else throw new IOException("invalid format defintion:"+format); OutputStream os=null; try { os=pc.getResponseStream(); setFormat(pc.getHttpServletResponse(), format, cs); IOUtil.copy(is, os, false,false); } finally { IOUtil.flushEL(os); IOUtil.closeEL(os); ((PageContextImpl)pc).getRootOut().setClosed(true); } } private Charset getCharset(PageContext pc) { HttpServletResponse rsp = pc.getHttpServletResponse(); String str = ReqRspUtil.getCharacterEncoding(pc,rsp); if(StringUtil.isEmpty(str)) str=pc.getConfig().getWebCharset(); return CharsetUtil.toCharset(str, CharsetUtil.UTF8); } private void callWSDL(PageContext pc, Component component) throws ServletException, IOException, ExpressionException { // take wsdl file defined by user String wsdl = component.getWSDLFile(); if(!StringUtil.isEmpty(wsdl)) { OutputStream os=null; Resource input = ResourceUtil.toResourceExisting(pc, wsdl); try { os=pc.getResponseStream(); pc.getResponse().setContentType("text/xml; charset=utf-8"); IOUtil.copy(input, os, false); } finally { IOUtil.flushEL(os); IOUtil.closeEL(os); ((PageContextImpl)pc).getRootOut().setClosed(true); } } // create a wsdl file else { RPCServer.getInstance(pc.getId(),pc.getServletContext()) .doGet(pc.getHttpServletRequest(), pc. getHttpServletResponse(), component); } } private void callWebservice(PageContext pc, Component component) throws IOException, ServletException { ComponentController.set(pc, component); try { RPCServer.getInstance(pc.getId(),pc.getServletContext()) .doPost(pc.getHttpServletRequest(), pc. getHttpServletResponse(), component); } finally { ComponentController.release(); } } public abstract void initComponent(PageContext pc,ComponentImpl c) throws PageException; public void ckecked() { lastCheck=System.currentTimeMillis(); } public long lastCheck() { return lastCheck; } } class Props { public String strType="any"; public boolean secureJson; public int type=CFTypes.TYPE_ANY; public int format=UDF.RETURN_FORMAT_WDDX; public boolean output=true; }