1 2 12 package com.versant.core.jdo.query.mem; 13 14 15 import com.versant.lib.bcel.Constants; 16 import com.versant.lib.bcel.classfile.JavaClass; 17 import com.versant.lib.bcel.generic.ClassGen; 18 import com.versant.lib.bcel.generic.InstructionFactory; 19 20 import com.versant.core.metadata.ClassMetaData; 21 import com.versant.core.metadata.ModelMetaData; 22 import com.versant.core.jdo.*; 23 import com.versant.core.jdo.query.ParamNode; 24 import com.versant.core.jdo.query.ParseException; 25 26 import java.util.HashMap ; 27 import java.util.Map ; 28 import java.lang.reflect.Method ; 29 import java.lang.reflect.InvocationTargetException ; 30 import java.io.File ; 31 import java.io.FileOutputStream ; 32 import java.io.IOException ; 33 34 import com.versant.core.common.BindingSupportImpl; 35 36 40 public class MemQueryCompiler { 41 42 private final ModelMetaData jmd; 43 private final ClassLoader loader; 44 private Map compiledQueryMap = new HashMap (); 45 private long clsCounter; 46 private Method defineClass; 47 48 public MemQueryCompiler(ModelMetaData jmd, ClassLoader loader) { 49 this.jmd = jmd; 50 this.loader = loader; 51 52 try { 53 defineClass = ClassLoader .class.getDeclaredMethod("defineClass", 54 new Class []{String .class, byte[].class, Integer.TYPE, 55 Integer.TYPE}); 56 } catch (NoSuchMethodException e) { 57 throw BindingSupportImpl.getInstance().internal(e.toString(), e); 59 } 60 defineClass.setAccessible(true); 61 62 } 63 64 public synchronized BCodeQuery compile(QueryDetails queryParams, Object [] params) { 65 BCodeQuery bCodeQuery = (BCodeQuery)compiledQueryMap.get(queryParams); 66 if (bCodeQuery != null) return bCodeQuery; 67 68 69 boolean toFilter = true; 70 if (queryParams.getFilter() == null || queryParams.getFilter().equals( 71 "true")) { 72 toFilter = false; 73 } else { 74 toFilter = true; 75 } 76 77 ClassMetaData classMetaData = jmd.getClassMetaData( 78 queryParams.getCandidateClass()); 79 String name = getQClsName(); 80 ClassGen classGen = new ClassGen(name, BCodeQuery.class.getName(), 81 "<generated>", Constants.ACC_PUBLIC | Constants.ACC_SUPER, 82 null); 83 InstructionFactory factory = new InstructionFactory(classGen); 84 classGen.addEmptyConstructor(Constants.ACC_PUBLIC); 85 86 CompiledMemQuery compiledMemQuery = new CompiledMemQuery(jmd); 87 try { 88 compiledMemQuery.compile(queryParams); 89 } catch (ParseException e) { 90 throw BindingSupportImpl.getInstance().exception(e.getMessage()); 91 } 92 93 if (toFilter) { 94 ByteCodeQVisitor byteCodeQVisitor = 95 new ByteCodeQVisitor(classGen, factory, name, 96 classMetaData, compiledMemQuery); 97 byteCodeQVisitor.setParamMap( 98 createParamMap(params, compiledMemQuery)); 99 compiledMemQuery.filter.visit(byteCodeQVisitor, null); 100 byteCodeQVisitor.finish(); 101 } 102 103 if (queryParams.getOrdering() != null) { 104 ByteCodeQCompareVisitor byteCodeQCompareVisitor = new ByteCodeQCompareVisitor( 105 classGen, factory, name, classMetaData); 106 for (int i = 0; i < compiledMemQuery.orders.length; i++) { 107 compiledMemQuery.orders[i].visit(byteCodeQCompareVisitor, null); 108 } 109 byteCodeQCompareVisitor.finish(); 110 } 111 112 JavaClass javaClass = classGen.getJavaClass(); 113 try { 114 bCodeQuery = (BCodeQuery)defineClass(javaClass.getBytes(), null).newInstance(); 115 compiledQueryMap.put(queryParams, bCodeQuery); 116 } catch (Exception e) { 117 if (BindingSupportImpl.getInstance().isOwnException(e)) { 118 throw (RuntimeException )e; 119 } 120 throw BindingSupportImpl.getInstance().internal(e.getMessage(), e); 121 } 122 123 return bCodeQuery; 124 } 125 126 private Map createParamMap(Object [] params, 127 CompiledMemQuery compiledMemQuery) { 128 Map m = new HashMap (); 129 if (compiledMemQuery.params == null) { 130 return m; 131 } 132 for (int i = 0; i < compiledMemQuery.params.length; i++) { 133 ParamNode param = compiledMemQuery.params[i]; 134 m.put(param.getIdentifier(), params[i]); 135 } 136 return m; 137 } 138 139 private Class defineClass(byte[] bytecode, File dir) { 140 try { 141 Class cls = (Class )defineClass.invoke(loader, new Object []{null, 142 bytecode, new Integer (0), new Integer (bytecode.length)}); 143 if (dir != null) { 144 File f = new File (dir, cls.getName() + ".class"); 145 try { 146 FileOutputStream o = new FileOutputStream (f); 147 o.write(bytecode, 0, bytecode.length); 148 o.close(); 149 } catch (IOException x) { 150 throw BindingSupportImpl.getInstance().runtime( 151 "Error writing to " + f + ": " + x, x); 152 } 153 } 154 return cls; 155 } catch (InvocationTargetException e) { 156 Throwable t = e.getTargetException(); 157 throw BindingSupportImpl.getInstance().internal(t.toString(), t); 158 } catch (Exception x) { 159 throw BindingSupportImpl.getInstance().internal(x.toString(), x); 160 } 161 } 162 163 private synchronized String getQClsName() { 164 return "VOA_QUERY_" + clsCounter++; 165 } 166 167 } 168 | Popular Tags |