001package com.hammurapi.extract.java; 002 003import java.util.ArrayList; 004import java.util.Collection; 005import java.util.Collections; 006import java.util.List; 007import java.util.Map; 008import java.util.Set; 009import java.util.concurrent.TimeUnit; 010 011import org.codehaus.commons.compiler.CompileException; 012import org.codehaus.janino.ExpressionEvaluator; 013 014import com.hammurapi.common.Identifiable; 015import com.hammurapi.extract.ComparisonResult; 016import com.hammurapi.extract.Extractor; 017import com.hammurapi.extract.ExtractorBase; 018import com.hammurapi.extract.ExtractorException; 019import com.hammurapi.extract.Mappable; 020 021public class JavaExtractor<T, V, C> extends ExtractorBase<T, V, C> implements Extractor<T, V, C> , Mappable<T,V,C>, Identifiable<List<Object>> { 022 023 private Params<T, C> params; 024 private Class<V> valueType; 025 private ClassLoader classLoader; 026 027 public JavaExtractor(double initialCost, TimeUnit costUnit, Params<T, C> params, Class<V> valueType, ClassLoader classLoader) { 028 super(initialCost, costUnit); 029 this.params = params; 030 this.valueType = valueType; 031 this.classLoader = classLoader; 032 } 033 034 private ThreadLocal<ExpressionEvaluator> eetl = new ThreadLocal<ExpressionEvaluator>() { 035 036 protected ExpressionEvaluator initialValue() { 037 try { 038 // TODO - Pass classLoader? 039 return new ExpressionEvaluator(params.expr.toString(), valueType, params.names, params.types); 040 } catch (CompileException e) { 041 throw new ExtractorException("Compile exception in code '"+params.expr+"': "+e, e); 042 } 043 }; 044 }; 045 046 @SuppressWarnings("unchecked") 047 @Override 048 protected V extractInternal(C context, Map<C, Map<Extractor<T, ? super V, C>, ? super V>> cache, T... obj) { 049 Object[] args = params.translate(obj, context); 050 try { 051 return (V) eetl.get().evaluate(args); 052 } catch (Exception e) { 053 throw new ExtractorException("Invocation exception in code '"+params.expr+"': "+e, e); 054 } 055 } 056 057 @Override 058 public boolean isContextDependent() { 059 return params.isContextDependent(); 060 } 061 062 @Override 063 public Set<Integer> parameterIndices() { 064 return params.indices; 065 } 066 067 @Override 068 public String toString() { 069 return getClass().getName()+"(code: '"+params.expr+"', parameter indices "+parameterIndices()+", cost: "+getCost()+")"; 070 } 071 072 @Override 073 public int hashCode() { 074 final int prime = 31; 075 int result = 1; 076 result = prime * result 077 + ((classLoader == null) ? 0 : classLoader.hashCode()); 078 result = prime * result + ((params == null) ? 0 : params.hashCode()); 079 result = prime * result 080 + ((valueType == null) ? 0 : valueType.hashCode()); 081 return result; 082 } 083 084 @Override 085 public ComparisonResult compareTo(Extractor<T, V, C> obj) { 086 if (this == obj) { 087 return ComparisonResult.EQUAL_NM; 088 } 089 if (obj == null) { 090 return ComparisonResult.NOT_EQUAL_NM; 091 } 092 093 if (getClass() != obj.getClass()) { 094 return super.compareTo(obj); // For parenthesis, facades and other stuff. 095 } 096 097 JavaExtractor other = (JavaExtractor) obj; 098 if (classLoader == null) { 099 if (other.classLoader != null) { 100 return ComparisonResult.NOT_EQUAL_NM; 101 } 102 } else if (!classLoader.equals(other.classLoader)) { 103 return ComparisonResult.NOT_EQUAL_NM; 104 } 105 106 if (params == null) { 107 if (other.params != null) { 108 return ComparisonResult.NOT_EQUAL_NM; 109 } 110 } else if (!params.equals(other.params)) { 111 return ComparisonResult.NOT_EQUAL_NM; 112 } 113 if (valueType == null) { 114 if (other.valueType != null){ 115 return ComparisonResult.NOT_EQUAL_NM; 116 } 117 } else if (!valueType.equals(other.valueType)) { 118 return ComparisonResult.NOT_EQUAL_NM; 119 } 120 return ComparisonResult.EQUAL_NM; 121 } 122 123 @SuppressWarnings("unchecked") 124 @Override 125 public Extractor<T, V, C> map(int[] map) { 126 if (ComparisonResult.isOneToOneMapping(map)) { 127 return this; 128 } 129 130 Params<T,C> newParams = params.map(map); 131 if (newParams==null) { 132 return null; 133 } 134 135 if (this instanceof JavaPredicate) { 136 return (Extractor<T, V, C>) new JavaPredicate<T, C>(initialCost, costUnit, newParams, classLoader); 137 } 138 139 return new JavaExtractor<T, V, C>(initialCost, costUnit, newParams, valueType, classLoader); 140 } 141 142 public List<Object> getIdentity() { 143 return params.getIdentity(); 144 } 145 146 public interface Parameter { 147 int getIndex(); 148 Class<?> getType(); 149 String getName(); 150 } 151 152 public Iterable<Parameter> getParameters() { 153 Collection<Parameter> ret = new ArrayList<Parameter>(); 154 final Integer[] ia = params.indices.toArray(new Integer[params.indices.size()]); 155 for (int i=0; i<params.names.length; ++i) { 156 class ParameterImpl implements Parameter { 157 158 private int idx; 159 160 public ParameterImpl(int idx) { 161 this.idx = idx; 162 } 163 164 @Override 165 public int getIndex() { 166 return ia[idx]; 167 } 168 169 @Override 170 public Class<?> getType() { 171 return params.types[idx]; 172 } 173 174 @Override 175 public String getName() { 176 return params.names[idx]; 177 } 178 179 @Override 180 public String toString() { 181 return "Parameter[idx=" + idx + ", type=" 182 + getType() + ", name=" + getName() + "]"; 183 } 184 185 186 } 187 188 ret.add(new ParameterImpl(i)); 189 190 } 191 192 return Collections.unmodifiableCollection(ret); 193 } 194 195 public String getExpression() { 196 return params.expr.toString(); 197 } 198}