001    package railo.runtime.type.util;
002    
003    import java.util.ArrayList;
004    import java.util.Iterator;
005    import java.util.Map.Entry;
006    
007    import railo.runtime.Page;
008    import railo.runtime.PageContext;
009    import railo.runtime.PagePlus;
010    import railo.runtime.PageSource;
011    import railo.runtime.exp.ApplicationException;
012    import railo.runtime.exp.PageException;
013    import railo.runtime.exp.PageExceptionImpl;
014    import railo.runtime.op.Decision;
015    import railo.runtime.type.Collection.Key;
016    import railo.runtime.type.KeyImpl;
017    import railo.runtime.type.Struct;
018    import railo.runtime.type.UDF;
019    import railo.runtime.type.UDFPlus;
020    import railo.transformer.library.function.FunctionLibFunction;
021    import railo.transformer.library.function.FunctionLibFunctionArg;
022    
023    public class UDFUtil {
024    
025            /**
026             * add detailed function documentation to the exception
027             * @param pe
028             * @param flf
029             */
030            public static void addFunctionDoc(PageExceptionImpl pe,FunctionLibFunction flf) {
031                    ArrayList<FunctionLibFunctionArg> args=flf.getArg();
032                    Iterator<FunctionLibFunctionArg> it = args.iterator();
033                    
034                    // Pattern
035                    StringBuilder pattern=new StringBuilder(flf.getName());
036                    StringBuilder end=new StringBuilder();
037                    pattern.append("(");
038                    FunctionLibFunctionArg arg;
039                    int c=0;
040                    while(it.hasNext()){
041                            arg = it.next();
042                            if(!arg.isRequired()) {
043                                    pattern.append(" [");
044                                    end.append("]");
045                            }
046                            if(c++>0)pattern.append(", ");
047                            pattern.append(arg.getName());
048                            pattern.append(":");
049                            pattern.append(arg.getTypeAsString());
050                            
051                    }
052                    pattern.append(end);
053                    pattern.append("):");
054                    pattern.append(flf.getReturnTypeAsString());
055                    
056                    pe.setAdditional(KeyConstants._Pattern, pattern);
057                    
058                    // Documentation
059                    StringBuilder doc=new StringBuilder(flf.getDescription());
060                    StringBuilder req=new StringBuilder();
061                    StringBuilder opt=new StringBuilder();
062                    StringBuilder tmp;
063                    doc.append("\n");
064                    
065                    it = args.iterator();
066                    while(it.hasNext()){
067                            arg = it.next();
068                            tmp=arg.isRequired()?req:opt;
069                            
070                            tmp.append("- ");
071                            tmp.append(arg.getName());
072                            tmp.append(" (");
073                            tmp.append(arg.getTypeAsString());
074                            tmp.append("): ");
075                            tmp.append(arg.getDescription());
076                            tmp.append("\n");
077                    }
078    
079                    if(req.length()>0)doc.append("\nRequired:\n").append(req);
080                    if(opt.length()>0)doc.append("\nOptional:\n").append(opt);
081                    
082                    
083                    pe.setAdditional(KeyImpl.init("Documentation"), doc);
084                    
085            }
086    
087            public static String callerHash(UDF udf, Object[] args, Struct values) throws ApplicationException {
088                    StringBuilder sb=new StringBuilder(udf.getPageSource().getDisplayPath())
089                            .append(';')
090                            .append(udf.getFunctionName())
091                            .append(';');
092                    
093                    if(values!=null) {
094                            Iterator<Entry<Key, Object>> it = values.entryIterator();
095                            Entry<Key, Object> e;
096                            while(it.hasNext()){
097                                    e = it.next();
098                                    if(!Decision.isSimpleValue(e.getValue())) throw new ApplicationException("only simple values are allowed as parameter for a function with cachedWithin");
099                                    sb.append(e.getKey().getString()).append(':').append(e.getValue()).append(';');
100                                    
101                            }
102                    }
103                    else if(args!=null){
104                            for(int i=0;i<args.length;i++){
105                                    if(!Decision.isSimpleValue(args[i])) throw new ApplicationException("only simple values are allowed as parameter for a function with cachedWithin");
106                                    sb.append(args[i]).append(';');
107                                    
108                            }
109                    }
110                    return sb.toString();
111            }
112    
113            public static Object getDefaultValue(PageContext pc, PageSource ps, int udfIndex, int index, Object defaultValue) throws PageException {
114                    Page p=ComponentUtil.getPage(pc,ps);
115            if(p instanceof PagePlus) return ((PagePlus)p).udfDefaultValue(pc,udfIndex,index,defaultValue);
116            Object rtn = p.udfDefaultValue(pc,udfIndex,index);
117            if(rtn==null) return defaultValue;// in that case it can make no diff between null and not existing, but this only happens with data from old ra files
118            return rtn;
119            }
120            
121    
122            public static Object getDefaultValue(PageContext pc, UDFPlus udf, int index, Object defaultValue) throws PageException {
123                    Page p=ComponentUtil.getPage(pc,udf.getPageSource());
124                    if(p instanceof PagePlus) return ((PagePlus)p).udfDefaultValue(pc,udf.getIndex(),index,defaultValue);
125                    Object rtn = p.udfDefaultValue(pc,udf.getIndex(),index);
126            if(rtn==null) return defaultValue;// in that case it can make no diff between null and not existing, but this only happens with data from old ra files
127            return rtn;
128            }
129    
130    }