1 2 12 package com.versant.core.storagemanager; 13 14 import com.versant.core.common.config.ConfigInfo; 15 import com.versant.core.common.config.ConfigParser; 16 import com.versant.core.metadata.parser.MetaDataParser; 17 import com.versant.core.metadata.ModelMetaData; 18 import com.versant.core.common.BindingSupportImpl; 19 import com.versant.core.common.Utils; 20 import com.versant.core.util.BeanUtils; 21 import com.versant.core.util.PropertiesLoader; 22 import com.versant.core.util.classhelper.ClassHelper; 23 import com.versant.core.logging.LogEventStore; 24 import com.versant.core.storagemanager.logging.LoggingStorageManagerFactory; 25 26 import com.versant.core.compiler.ClassCompiler; 27 import com.versant.core.compiler.PizzaClassCompiler; 28 import com.versant.core.compiler.ClassSpec; 29 30 import com.versant.core.server.CompiledQueryCache; 31 32 import java.util.*; 33 import java.util.zip.Deflater ; 34 import java.lang.reflect.Method ; 35 import java.lang.reflect.InvocationTargetException ; 36 import java.lang.reflect.Constructor ; 37 import java.io.*; 38 39 43 public class StorageManagerFactoryBuilder { 44 45 private ConfigInfo config; 46 private ClassLoader loader; 47 private LogEventStore pes; 48 private StorageCache cache; 49 private boolean onlyMetaData; 50 private boolean fullInit = true; 51 private boolean continueAfterMetaDataError; 52 53 private ClassCompiler classCompiler; 54 55 private HashMap classSpecs; 56 private CompiledQueryCache compiledQueryCache; 57 private boolean keepHyperdriveBytecode; 58 private Map hyperdriveBytecode; 59 private int hyperdriveBytecodeMaxSize; 60 61 public StorageManagerFactoryBuilder() { 62 } 63 64 67 public StorageManagerFactory createStorageManagerFactory() { 68 69 if (config == null) { 70 throw BindingSupportImpl.getInstance().internal( 71 "config property not set"); 72 } 73 74 75 if (loader == null) { 76 throw BindingSupportImpl.getInstance().internal( 77 "loader property not set"); 78 } 79 if (Utils.isStringEmpty(config.url)) { 80 if (Utils.isStringEmpty(config.props.getProperty( 81 ConfigParser.OPTION_CONNECTION_FACTORY_NAME)) && 82 !Utils.isDataSource(config.props.getProperty( 83 ConfigParser.STD_CON_DRIVER_NAME), loader)) { 84 85 throw BindingSupportImpl.getInstance().internal( 86 "javax.jdo.option.ConnectionURL property is required " + 87 "if using a JDBC Driver"); 88 89 } else if (Utils.isStringEmpty(config.db)){ 90 throw BindingSupportImpl.getInstance().internal( 91 ConfigParser.STORE_DB + 92 " property is required if using a JDBC DataSource"); 93 } 94 95 } 96 97 98 if (cache == null) { 99 cache = new NOPStorageCache(); 100 } 101 if (pes == null) { 102 pes = new LogEventStore(); 103 BeanUtils.setProperties(pes, config.perfProps); 104 } 105 if (config.jdoMetaData == null) { 106 MetaDataParser p = new MetaDataParser(); 107 config.jdoMetaData = p.parse(config.jdoResources, loader); 108 } 109 if (config.hyperdrive) { 110 classSpecs = new HashMap(); 111 } else { 112 classSpecs = null; 113 } 114 compiledQueryCache = new CompiledQueryCache( 115 config.compiledQueryCacheSize); 116 StorageManagerFactory smf = createSmfForURL(); 117 ModelMetaData jmd = smf.getModelMetaData(); 118 jmd.forceClassRegistration(); 119 cache.setJDOMetaData(jmd); 120 smf = new LoggingStorageManagerFactory(smf, pes); 121 122 123 if (config.hyperdrive && !classSpecs.isEmpty()) { 124 if (config.hyperdriveSrcDir != null) { 125 writeGeneratedSourceCode(classSpecs, config.hyperdriveSrcDir); 126 } 127 if (!onlyMetaData || config.hyperdriveClassDir != null) { 128 compileAndInitGeneratedClasses(config.hyperdriveClassDir, jmd); 129 } 130 } 131 132 133 if (!onlyMetaData) { 134 smf.init(fullInit, loader); 135 } 136 return smf; 137 } 138 139 private StorageManagerFactory createSmfForURL() { 140 StorageManagerFactory smf; 141 Properties p; 142 143 try { 144 if (!Utils.isStringEmpty(config.db)){ 145 p = PropertiesLoader.loadPropertiesForDB(loader, "openaccess", 146 config.db); 147 } else { 148 p = PropertiesLoader.loadPropertiesForURL(loader, "openaccess", 149 config.url); 150 } 151 } catch (IOException e) { 152 throw BindingSupportImpl.getInstance().invalidOperation( 153 e.toString(), e); 154 } 155 156 157 String resName = p.getProperty(PropertiesLoader.RES_NAME_PROP); 158 String smfClassName = p.getProperty("smf"); 159 if (smfClassName == null) { 160 throw BindingSupportImpl.getInstance().internal( 161 "No 'smf' property in " + resName); 162 } 163 try { 164 Class cls = ClassHelper.get().classForName(smfClassName, true, loader); 165 Constructor cons = cls.getConstructor( 166 new Class []{StorageManagerFactoryBuilder.class}); 167 smf = (StorageManagerFactory)cons.newInstance(new Object []{this}); 168 } catch (Throwable e) { 169 if (BindingSupportImpl.getInstance().isError(e) && !BindingSupportImpl.getInstance().isOutOfMemoryError(e)) { 170 throw (Error )e; 171 } 172 if (BindingSupportImpl.getInstance().isOwnException(e)) { 173 throw (RuntimeException )e; 174 } 175 if( e instanceof InvocationTargetException && ((InvocationTargetException )e).getTargetException() != null ) 176 { 177 Throwable inner = ((InvocationTargetException )e).getTargetException(); 178 if (BindingSupportImpl.getInstance().isOwnException(inner)) 179 throw (RuntimeException )inner; 180 else 181 throw BindingSupportImpl.getInstance().internal( inner.toString(), 182 inner ); 183 } 184 else 185 { 186 throw BindingSupportImpl.getInstance().internal(e.toString(), e); 187 } 188 } 189 return smf; 190 } 191 192 196 197 private void compileAndInitGeneratedClasses(String hyperdriveClassDir, 198 ModelMetaData jmd) { 199 ArrayList toInit = new ArrayList(); 202 ArrayList notGenerated = new ArrayList(); 203 Map toCompile = new HashMap(); 204 for (Iterator i = classSpecs.entrySet().iterator(); i.hasNext(); ) { 205 Map.Entry e = (Map.Entry)i.next(); 206 String name = (String )e.getKey(); 207 ClassSpec spec = (ClassSpec)e.getValue(); 208 try { 209 toInit.add(Class.forName(name, false, loader)); 210 notGenerated.add(name); 211 } catch (ClassNotFoundException x) { 212 toCompile.put(name, spec.toSrcCode()); 213 } 214 i.remove(); } 216 classSpecs = null; 217 218 if (!toCompile.isEmpty()) { 220 if (classCompiler == null) { 221 classCompiler = new PizzaClassCompiler(); 222 } 223 Map compiled = classCompiler.compile(toCompile, loader); 224 classCompiler = null; 225 if (hyperdriveClassDir != null) { 226 writeClassFiles(compiled, hyperdriveClassDir); 227 } 228 loadCompiledClasses(compiled, toInit); 229 if (keepHyperdriveBytecode) { 230 hyperdriveBytecode = compiled; 231 } 232 } 233 234 initHyperdriveClasses(toInit, jmd); 235 236 if (keepHyperdriveBytecode) { 237 if (hyperdriveBytecode == null) { 239 hyperdriveBytecode = new HashMap(); 240 } 241 for (int i = notGenerated.size() - 1; i >= 0; i--) { 242 hyperdriveBytecode.put(notGenerated.get(i), null); 243 } 244 } 245 } 246 247 248 253 254 public static void initHyperdriveClasses(List toInit, ModelMetaData jmd) { 255 for (Iterator i = toInit.iterator(); i.hasNext(); ) { 256 Class cls = (Class )i.next(); 257 Object res = null; 258 try { 259 Method m = cls.getMethod("initStatics", 260 new Class []{ModelMetaData.class}); 261 res = m.invoke(null, new Object []{jmd}); 262 } catch (NoSuchMethodException e) { 263 } catch (InvocationTargetException e) { 265 Throwable t = e.getTargetException(); 266 throw BindingSupportImpl.getInstance().internal(t.toString(), t); 267 } catch (Exception x) { 268 throw BindingSupportImpl.getInstance().internal(x.toString(), x); 269 } 270 if (res instanceof Boolean ) { 271 if (!((Boolean )res).booleanValue()) { 272 throw BindingSupportImpl.getInstance().internal( 273 cls.getName() + " is in use (try versant.useClassloader=true)"); 274 } 275 } 276 } 277 } 278 279 280 287 288 private void loadCompiledClasses(Map map, Collection toInit) { 289 ArrayList names = new ArrayList(map.keySet()); 290 Collections.sort(names); 291 Method defineClass = null; 292 try { 293 defineClass = ClassLoader .class.getDeclaredMethod("defineClass", 294 new Class []{String .class, byte[].class, Integer.TYPE, 295 Integer.TYPE}); 296 } catch (NoSuchMethodException e) { 297 throw BindingSupportImpl.getInstance().internal(e.toString(), e); 299 } 300 defineClass.setAccessible(true); 301 Deflater def = null; 302 byte[] outbuf = null; 303 if (keepHyperdriveBytecode) { 304 def = new Deflater (9); 305 hyperdriveBytecodeMaxSize = 0; 306 for (Iterator i = map.entrySet().iterator(); i.hasNext(); ) { 307 byte[] bytecode = (byte[])((Map.Entry)i.next()).getValue(); 308 if (bytecode.length > hyperdriveBytecodeMaxSize) { 309 hyperdriveBytecodeMaxSize = bytecode.length; 310 } 311 } 312 outbuf = new byte[hyperdriveBytecodeMaxSize + 128]; 313 } 314 for (Iterator i = names.iterator(); i.hasNext(); ) { 315 Object className = i.next(); 316 byte[] bytecode = (byte[])map.get(className); 317 try { 318 Class cls = (Class )defineClass.invoke(loader, new Object []{null, 319 bytecode, new Integer (0), new Integer (bytecode.length)}); 320 toInit.add(cls); 321 } catch (InvocationTargetException e) { 322 Throwable t = e.getTargetException(); 323 throw BindingSupportImpl.getInstance().internal(t.toString(), t); 324 } catch (Exception x) { 325 throw BindingSupportImpl.getInstance().internal(x.toString(), x); 326 } 327 if (keepHyperdriveBytecode) { 328 def.reset(); 329 def.setInput(bytecode); 330 def.finish(); 331 int sz = def.deflate(outbuf); 332 bytecode = new byte[sz]; 333 System.arraycopy(outbuf, 0, bytecode, 0, sz); 334 map.put(className, bytecode); 335 } else { 336 map.remove(className); 337 } 338 } 339 } 340 341 342 345 346 private void writeClassFiles(Map map, String dir) { 347 for (Iterator i = map.entrySet().iterator(); i.hasNext(); ) { 348 Map.Entry e = (Map.Entry)i.next(); 349 String className = (String )e.getKey(); 350 byte[] bytecode = (byte[])e.getValue(); 351 File f = new File(dir, className + ".class"); 352 try { 353 FileOutputStream o = new FileOutputStream(f); 354 o.write(bytecode, 0, bytecode.length); 355 o.close(); 356 } catch (IOException x) { 357 throw BindingSupportImpl.getInstance().runtime( 358 "Error writing to " + f + ": " + x, x); 359 } 360 } 361 } 362 363 364 367 368 private void writeGeneratedSourceCode(HashMap classSpecs, String dir) { 369 for (Iterator i = classSpecs.entrySet().iterator(); i.hasNext(); ) { 370 Map.Entry e = (Map.Entry)i.next(); 371 ClassSpec spec = (ClassSpec)e.getValue(); 372 File f = new File(dir, spec.getName() + ".java"); 373 try { 374 FileWriter o = new FileWriter(f); 375 o.write(spec.toSrcCode()); 376 o.close(); 377 } catch (IOException x) { 378 throw BindingSupportImpl.getInstance().runtime( 379 "Error writing to " + f + ": " + x, x); 380 } 381 } 382 } 383 384 385 public ConfigInfo getConfig() { 386 return config; 387 } 388 389 public void setConfig(ConfigInfo config) { 390 this.config = config; 391 } 392 393 public ClassLoader getLoader() { 394 return loader; 395 } 396 397 public void setLoader(ClassLoader loader) { 398 this.loader = loader; 399 } 400 401 public LogEventStore getLogEventStore() { 402 return pes; 403 } 404 405 public void setLogEventStore(LogEventStore logEventStore) { 406 this.pes = logEventStore; 407 } 408 409 public StorageCache getCache() { 410 return cache; 411 } 412 413 public void setCache(StorageCache cache) { 414 this.cache = cache; 415 } 416 417 public boolean isOnlyMetaData() { 418 return onlyMetaData; 419 } 420 421 425 public void setOnlyMetaData(boolean onlyMetaData) { 426 this.onlyMetaData = onlyMetaData; 427 } 428 429 public boolean isFullInit() { 430 return fullInit; 431 } 432 433 438 public void setFullInit(boolean fullInit) { 439 this.fullInit = fullInit; 440 } 441 442 443 public ClassCompiler getClassCompiler() { 444 return classCompiler; 445 } 446 447 public void setClassCompiler(ClassCompiler classCompiler) { 448 this.classCompiler = classCompiler; 449 } 450 451 452 public boolean isContinueAfterMetaDataError() { 453 return continueAfterMetaDataError; 454 } 455 456 462 public void setContinueAfterMetaDataError(boolean continueAfterMetaDataError) { 463 this.continueAfterMetaDataError = continueAfterMetaDataError; 464 } 465 466 471 public HashMap getClassSpecs() { 472 return classSpecs; 473 } 474 475 478 public CompiledQueryCache getCompiledQueryCache() { 479 return compiledQueryCache; 480 } 481 482 487 public void setKeepHyperdriveBytecode(boolean keepHyperdriveBytecode) { 488 this.keepHyperdriveBytecode = keepHyperdriveBytecode; 489 } 490 491 public boolean isKeepHyperdriveBytecode() { 492 return keepHyperdriveBytecode; 493 } 494 495 504 public Map getHyperdriveBytecode() { 505 return hyperdriveBytecode; 506 } 507 508 516 public int getHyperdriveBytecodeMaxSize() { 517 return hyperdriveBytecodeMaxSize; 518 } 519 520 } 521 522 | Popular Tags |