001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/FunInfo.java#14 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2005-2007 Julian Hyde and others 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 011 package mondrian.olap.fun; 012 013 import mondrian.olap.FunDef; 014 import mondrian.olap.Syntax; 015 import mondrian.olap.Util; 016 017 import java.util.*; 018 import java.lang.reflect.Array; 019 020 /** 021 * Support class for the {@link mondrian.tui.CmdRunner} allowing one to view 022 * available functions and their syntax. 023 * 024 * @author Richard M. Emberson 025 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/FunInfo.java#14 $ 026 */ 027 public class FunInfo implements Comparable<FunInfo> { 028 private final Syntax syntax; 029 private final String name; 030 private final String description; 031 private final int[] returnTypes; 032 private final int[][] parameterTypes; 033 private String[] sigs; 034 035 static FunInfo make(Resolver resolver) { 036 FunDef funDef = resolver.getFunDef(); 037 if (funDef != null) { 038 return new FunInfo(funDef); 039 } else if (resolver instanceof MultiResolver) { 040 return new FunInfo((MultiResolver) resolver); 041 } else { 042 return new FunInfo(resolver); 043 } 044 } 045 046 FunInfo(FunDef funDef) { 047 this.syntax = funDef.getSyntax(); 048 this.name = funDef.getName(); 049 assert name != null; 050 assert syntax != null; 051 this.returnTypes = new int[] { funDef.getReturnCategory() }; 052 this.parameterTypes = new int[][] { funDef.getParameterCategories() }; 053 054 // use explicit signature if it has one, otherwise generate a set 055 this.sigs = funDef instanceof FunDefBase 056 && ((FunDefBase) funDef).signature != null 057 ? new String[] {((FunDefBase) funDef).signature} 058 : makeSigs(syntax, name, returnTypes, parameterTypes); 059 this.description = funDef.getDescription(); 060 } 061 062 FunInfo(MultiResolver multiResolver) { 063 this.syntax = multiResolver.getSyntax(); 064 this.name = multiResolver.getName(); 065 assert name != null; 066 assert syntax != null; 067 this.description = multiResolver.getDescription(); 068 069 String[] signatures = multiResolver.getSignatures(); 070 this.returnTypes = new int[signatures.length]; 071 this.parameterTypes = new int[signatures.length][]; 072 for (int i = 0; i < signatures.length; i++) { 073 returnTypes[i] = FunUtil.decodeReturnCategory(signatures[i]); 074 parameterTypes[i] = FunUtil.decodeParameterCategories(signatures[i]); 075 } 076 this.sigs = makeSigs(syntax, name, returnTypes, parameterTypes); 077 } 078 079 FunInfo(Resolver resolver) { 080 this.syntax = resolver.getSyntax(); 081 this.name = resolver.getName(); 082 assert name != null; 083 assert syntax != null; 084 this.description = resolver.getDescription(); 085 this.returnTypes = null; 086 this.parameterTypes = null; 087 final String signature = resolver.getSignature(); 088 this.sigs = signature == null ? new String[0] : 089 new String[] {signature}; 090 } 091 092 public String[] getSignatures() { 093 return sigs; 094 } 095 096 private static String[] makeSigs( 097 Syntax syntax, 098 String name, 099 int[] returnTypes, 100 int[][] parameterTypes) 101 { 102 if (parameterTypes == null) { 103 return null; 104 } 105 106 String[] sigs = new String[parameterTypes.length]; 107 for (int i = 0; i < sigs.length; i++) { 108 sigs[i] = syntax.getSignature( 109 name, returnTypes[i], parameterTypes[i]); 110 } 111 return sigs; 112 } 113 114 /** 115 * Returns the syntactic type of the function. 116 */ 117 public Syntax getSyntax() { 118 return this.syntax; 119 } 120 121 /** 122 * Returns the name of this function. 123 */ 124 public String getName() { 125 return this.name; 126 } 127 128 /** 129 * Returns the description of this function. 130 */ 131 public String getDescription() { 132 return this.description; 133 } 134 135 /** 136 * Returns the type of value returned by this function. Values are the same 137 * as those returned by {@link mondrian.olap.Exp#getCategory()}. 138 */ 139 public int[] getReturnCategories() { 140 return this.returnTypes; 141 } 142 143 /** 144 * Returns the types of the arguments of this function. Values are the same 145 * as those returned by {@link mondrian.olap.Exp#getCategory()}. The 146 * 0<sup>th</sup> argument of methods and properties are the object they 147 * are applied to. Infix operators have two arguments, and prefix operators 148 * have one argument. 149 */ 150 public int[][] getParameterCategories() { 151 return this.parameterTypes; 152 } 153 154 public int compareTo(FunInfo fi) { 155 int c = this.name.compareTo(fi.name); 156 if (c != 0) { 157 return c; 158 } 159 final List<Object> pcList = toList(this.getParameterCategories()); 160 final String pc = pcList.toString(); 161 final List otherPcList = toList(fi.getParameterCategories()); 162 final String otherPc = otherPcList.toString(); 163 return pc.compareTo(otherPc); 164 } 165 166 public boolean equals(Object obj) { 167 if (obj instanceof FunInfo) { 168 final FunInfo that = (FunInfo) obj; 169 if (!name.equals(that.name)) { 170 return false; 171 } 172 final List<Object> pcList = toList(this.getParameterCategories()); 173 final List<Object> pcList2 = toList(that.getParameterCategories()); 174 return pcList.equals(pcList2); 175 } else { 176 return false; 177 } 178 } 179 180 public int hashCode() { 181 int h = name.hashCode(); 182 final List<Object> pcList = toList(this.getParameterCategories()); 183 return Util.hash(h, pcList); 184 } 185 186 private static List<Object> toList(Object a) { 187 final List<Object> list = new ArrayList<Object>(); 188 if (a == null) { 189 return list; 190 } 191 final int length = Array.getLength(a); 192 for (int i = 0; i < length; i++) { 193 final Object o = Array.get(a, i); 194 if (o.getClass().isArray()) { 195 list.add(toList(o)); 196 } else { 197 list.add(o); 198 } 199 } 200 return list; 201 } 202 } 203 204 // End FunInfo.java