001// SECTION-START[License Header] 002// <editor-fold defaultstate="collapsed" desc=" Generated License "> 003/* 004 * Java Object Management and Configuration 005 * Copyright (C) Christian Schulte, 2011-313 006 * All rights reserved. 007 * 008 * Redistribution and use in source and binary forms, with or without 009 * modification, are permitted provided that the following conditions 010 * are met: 011 * 012 * o Redistributions of source code must retain the above copyright 013 * notice, this list of conditions and the following disclaimer. 014 * 015 * o Redistributions in binary form must reproduce the above copyright 016 * notice, this list of conditions and the following disclaimer in 017 * the documentation and/or other materials provided with the 018 * distribution. 019 * 020 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 021 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 022 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 023 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, 024 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 025 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 026 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 027 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 029 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 030 * 031 * $JOMC: RuntimeInstance.java 4588 2012-06-03 06:01:30Z schulte2005 $ 032 * 033 */ 034// </editor-fold> 035// SECTION-END 036package org.jomc.ri.model; 037 038import java.lang.ref.Reference; 039import java.lang.ref.WeakReference; 040import java.lang.reflect.Constructor; 041import java.lang.reflect.Method; 042import java.util.Map; 043import javax.xml.bind.annotation.XmlTransient; 044import org.jomc.model.Instance; 045import org.jomc.model.Specification; 046import org.jomc.util.WeakIdentityHashMap; 047import static org.jomc.ri.model.RuntimeModelObjects.BOOTSTRAP_CLASSLOADER_KEY; 048import static org.jomc.ri.model.RuntimeModelObjects.classesByClassLoaderAndNameCache; 049import static org.jomc.ri.model.RuntimeModelObjects.createMap; 050 051// SECTION-START[Documentation] 052// <editor-fold defaultstate="collapsed" desc=" Generated Documentation "> 053/** 054 * Runtime {@code Instance}. 055 * 056 * <dl> 057 * <dt><b>Identifier:</b></dt><dd>org.jomc.ri.model.RuntimeInstance</dd> 058 * <dt><b>Name:</b></dt><dd>JOMC RI RuntimeInstance</dd> 059 * <dt><b>Specifications:</b></dt> 060 * <dd>org.jomc.ri.model.RuntimeModelObject @ 1.2</dd> 061 * <dt><b>Abstract:</b></dt><dd>No</dd> 062 * <dt><b>Final:</b></dt><dd>No</dd> 063 * <dt><b>Stateless:</b></dt><dd>No</dd> 064 * </dl> 065 * 066 * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a> 1.2 067 * @version 1.2 068 */ 069// </editor-fold> 070// SECTION-END 071// SECTION-START[Annotations] 072// <editor-fold defaultstate="collapsed" desc=" Generated Annotations "> 073@javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.3", comments = "See http://jomc.sourceforge.net/jomc/1.3/jomc-tools-1.3" ) 074// </editor-fold> 075// SECTION-END 076public class RuntimeInstance extends Instance implements RuntimeModelObject 077{ 078 // SECTION-START[RuntimeInstance] 079 080 /** Classes by class loader any instance cache. */ 081 @XmlTransient 082 static final Map<ClassLoader, Map<String, Reference<Class<?>[]>>> classesByClassLoaderAndInstanceCache = 083 new WeakIdentityHashMap<ClassLoader, Map<String, Reference<Class<?>[]>>>(); 084 085 /** Constructors by class loader any instance cache. */ 086 @XmlTransient 087 static final Map<ClassLoader, Map<String, Reference<Constructor<?>>>> constructorsByClassLoaderAndInstanceCache = 088 new WeakIdentityHashMap<ClassLoader, Map<String, Reference<Constructor<?>>>>(); 089 090 /** Methods by class loader any instance cache. */ 091 @XmlTransient 092 static final Map<ClassLoader, Map<String, Reference<Method>>> methodsByClassLoaderAndInstanceCache = 093 new WeakIdentityHashMap<ClassLoader, Map<String, Reference<Method>>>(); 094 095 /** Assignable flags by class loader any instance cache. */ 096 @XmlTransient 097 static final Map<ClassLoader, Map<String, Boolean>> assignableFlagsByClassLoaderAndInstanceCache = 098 new WeakIdentityHashMap<ClassLoader, Map<String, Boolean>>(); 099 100 /** Proxy classes by class loader any instance cache. */ 101 @XmlTransient 102 static final Map<ClassLoader, Map<String, Reference<Class<?>>>> proxyClassesByClassLoaderAndInstanceCache = 103 new WeakIdentityHashMap<ClassLoader, Map<String, Reference<Class<?>>>>(); 104 105 /** Method name. */ 106 @XmlTransient 107 private volatile String javaClassFactoryMethodName; 108 109 /** 110 * Creates a new {@code RuntimeInstance} instance by deeply copying a given {@code Instance} instance. 111 * 112 * @param instance The instance to copy. 113 * 114 * @throws NullPointerException if {@code instance} is {@code null}. 115 */ 116 public RuntimeInstance( final Instance instance ) 117 { 118 super( instance ); 119 120 if ( this.getAuthors() != null ) 121 { 122 this.setAuthors( RuntimeModelObjects.getInstance().copyOf( this.getAuthors() ) ); 123 } 124 if ( this.getDependencies() != null ) 125 { 126 this.setDependencies( RuntimeModelObjects.getInstance().copyOf( this.getDependencies() ) ); 127 } 128 if ( this.getDocumentation() != null ) 129 { 130 this.setDocumentation( RuntimeModelObjects.getInstance().copyOf( this.getDocumentation() ) ); 131 } 132 if ( this.getMessages() != null ) 133 { 134 this.setMessages( RuntimeModelObjects.getInstance().copyOf( this.getMessages() ) ); 135 } 136 if ( this.getProperties() != null ) 137 { 138 this.setProperties( RuntimeModelObjects.getInstance().copyOf( this.getProperties() ) ); 139 } 140 if ( this.getSpecifications() != null ) 141 { 142 this.setSpecifications( RuntimeModelObjects.getInstance().copyOf( this.getSpecifications() ) ); 143 } 144 } 145 146 /** 147 * Gets the Java class of the instance for a given class loader. 148 * <p>This method queries an internal cache for a result object to return for the given argument values. If no 149 * cached result object is available, this method queries the super-class for a result object to return and caches 150 * the outcome of that query for use on successive calls.</p> 151 * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the 152 * internal cache with the state of the class loader, should the state of the class loader change.</p> 153 * 154 * @param classLoader The class loader to get the Java class from or {@code null}, to get the Java class from the 155 * platform's bootstrap class loader. 156 * 157 * @return The Java class of the instance. 158 * 159 * @throws ClassNotFoundException if the Java class is not found. 160 * 161 * @see #getClazz() 162 * @see RuntimeModelObjects#clear() 163 */ 164 @Override 165 public Class<?> getJavaClass( final ClassLoader classLoader ) throws ClassNotFoundException 166 { 167 ClassLoader classLoaderKey = classLoader; 168 if ( classLoaderKey == null ) 169 { 170 classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY; 171 } 172 173 synchronized ( classesByClassLoaderAndNameCache ) 174 { 175 Class<?> javaClass = null; 176 Map<String, Reference<Class<?>>> map = classesByClassLoaderAndNameCache.get( classLoaderKey ); 177 178 if ( map == null ) 179 { 180 map = createMap(); 181 classesByClassLoaderAndNameCache.put( classLoaderKey, map ); 182 } 183 184 final Reference<Class<?>> reference = map.get( this.getClazz() ); 185 186 if ( reference != null ) 187 { 188 javaClass = reference.get(); 189 } 190 191 if ( javaClass == null ) 192 { 193 javaClass = super.getJavaClass( classLoader ); 194 map.put( this.getClazz(), new WeakReference<Class<?>>( javaClass ) ); 195 } 196 197 return javaClass; 198 } 199 } 200 201 /** 202 * Gets the Java classes of all specifications of the instance for a given class loader. 203 * <p>This method queries an internal cache for a result object to return for the given argument values. If no 204 * cached result object is available, this method queries the super-class for a result object to return and caches 205 * the outcome of that query for use on successive calls.</p> 206 * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the 207 * internal cache with the state of the instance and class loader, should the state of the instance or class loader 208 * change.</p> 209 * 210 * @param classLoader The class loader to get the Java classes from or {@code null}, to get the Java classes from 211 * the platform's bootstrap class loader. 212 * 213 * @return The Java classes of all specifications of the instance. 214 * 215 * @throws ClassNotFoundException if a Java class is not found. 216 * 217 * @see #getSpecifications() 218 * @see Specification#getClazz() 219 * @see RuntimeModelObjects#clear() 220 */ 221 @Override 222 public Class<?>[] getJavaClasses( final ClassLoader classLoader ) throws ClassNotFoundException 223 { 224 ClassLoader classLoaderKey = classLoader; 225 if ( classLoaderKey == null ) 226 { 227 classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY; 228 } 229 230 synchronized ( classesByClassLoaderAndInstanceCache ) 231 { 232 Class<?>[] javaClasses = null; 233 Map<String, Reference<Class<?>[]>> map = classesByClassLoaderAndInstanceCache.get( classLoaderKey ); 234 235 if ( map == null ) 236 { 237 map = createMap(); 238 classesByClassLoaderAndInstanceCache.put( classLoaderKey, map ); 239 } 240 241 final Reference<Class<?>[]> reference = map.get( this.getIdentifier() ); 242 243 if ( reference != null ) 244 { 245 javaClasses = reference.get(); 246 } 247 248 if ( javaClasses == null && ( reference != null || !map.containsKey( this.getIdentifier() ) ) ) 249 { 250 javaClasses = super.getJavaClasses( classLoader ); 251 map.put( this.getIdentifier(), new WeakReference<Class<?>[]>( javaClasses ) ); 252 } 253 254 return javaClasses; 255 } 256 } 257 258 /** 259 * Gets the Java constructor to use for creating objects of the instance. 260 * <p>This method queries an internal cache for a result object to return for the given argument values. If no 261 * cached result object is available, this method queries the super-class for a result object to return and caches 262 * the outcome of that query for use on successive calls.</p> 263 * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the 264 * internal cache with the state of the instance and class loader, should the state of the instance or class loader 265 * change.</p> 266 * 267 * @param classLoader The class loader to get the Java class from or {@code null}, to get the Java class from the 268 * platform's bootstrap class loader. 269 * 270 * @return The public default Java constructor of the Java class of the instance or {@code null}, if that class 271 * does not declare such a constructor, is abstract or is not public. 272 * 273 * @throws ClassNotFoundException if the Java class is not found. 274 * 275 * @see #getJavaClass(java.lang.ClassLoader) 276 * @see RuntimeModelObjects#clear() 277 */ 278 @Override 279 public Constructor<?> getJavaConstructor( final ClassLoader classLoader ) throws ClassNotFoundException 280 { 281 ClassLoader classLoaderKey = classLoader; 282 if ( classLoaderKey == null ) 283 { 284 classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY; 285 } 286 287 synchronized ( constructorsByClassLoaderAndInstanceCache ) 288 { 289 Constructor<?> javaClassConstructor = null; 290 Map<String, Reference<Constructor<?>>> map = constructorsByClassLoaderAndInstanceCache.get( classLoaderKey ); 291 292 if ( map == null ) 293 { 294 map = createMap(); 295 constructorsByClassLoaderAndInstanceCache.put( classLoaderKey, map ); 296 } 297 298 final Reference<Constructor<?>> reference = map.get( this.getIdentifier() ); 299 300 if ( reference != null ) 301 { 302 javaClassConstructor = reference.get(); 303 } 304 305 if ( javaClassConstructor == null && ( reference != null || !map.containsKey( this.getIdentifier() ) ) ) 306 { 307 javaClassConstructor = super.getJavaConstructor( classLoader ); 308 map.put( this.getIdentifier(), new WeakReference<Constructor<?>>( javaClassConstructor ) ); 309 } 310 311 return javaClassConstructor; 312 } 313 } 314 315 /** 316 * Gets the name of the Java method to use for creating objects of the instance. 317 * <p>This method queries an internal cache for a result object to return. If no cached result object is available, 318 * this method queries the super-class for a result object to return and caches the outcome of that query for use on 319 * successive calls.</p> 320 * <p><b>Note:</b><br/>Method {@code clear()} must be used to synchronize the state of the internal cache with the 321 * state of the instance, should the state of the instance change.</p> 322 * 323 * @return The name of the Java method to use for creating objects of the instance or {@code null}, if no such 324 * method name is supported. 325 * 326 * @see #getName() 327 * @see #clear() 328 */ 329 @Override 330 public String getJavaFactoryMethodName() 331 { 332 if ( this.javaClassFactoryMethodName == null ) 333 { 334 this.javaClassFactoryMethodName = super.getJavaFactoryMethodName(); 335 } 336 337 return this.javaClassFactoryMethodName; 338 } 339 340 /** 341 * Gets the Java method to use for creating objects of the instance. 342 * <p>This method queries an internal cache for a result object to return for the given argument values. If no 343 * cached result object is available, this method queries the super-class for a result object to return and caches 344 * the outcome of that query for use on successive calls.</p> 345 * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the 346 * internal cache with the state of the instance and class loader, should the state of the instance or class loader 347 * change.</p> 348 * 349 * @param classLoader The class loader to get the Java class from or {@code null}, to get the Java class from the 350 * platform's bootstrap class loader. 351 * 352 * @return The public Java method of the Java class of the instance to use for creating objects of the instance or 353 * {@code null}, if that class does not declare such a method. 354 * 355 * @throws ClassNotFoundException if the Java class is not found. 356 * 357 * @see #getJavaClass(java.lang.ClassLoader) 358 * @see #getJavaFactoryMethodName() 359 * @see RuntimeModelObjects#clear() 360 */ 361 @Override 362 public Method getJavaFactoryMethod( final ClassLoader classLoader ) throws ClassNotFoundException 363 { 364 ClassLoader classLoaderKey = classLoader; 365 if ( classLoaderKey == null ) 366 { 367 classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY; 368 } 369 370 synchronized ( methodsByClassLoaderAndInstanceCache ) 371 { 372 Method javaClassFactoryMethod = null; 373 Map<String, Reference<Method>> map = methodsByClassLoaderAndInstanceCache.get( classLoaderKey ); 374 375 if ( map == null ) 376 { 377 map = createMap(); 378 methodsByClassLoaderAndInstanceCache.put( classLoaderKey, map ); 379 } 380 381 final Reference<Method> reference = map.get( this.getIdentifier() ); 382 383 if ( reference != null ) 384 { 385 javaClassFactoryMethod = reference.get(); 386 } 387 388 if ( javaClassFactoryMethod == null && ( reference != null || !map.containsKey( this.getIdentifier() ) ) ) 389 { 390 javaClassFactoryMethod = super.getJavaFactoryMethod( classLoader ); 391 map.put( this.getIdentifier(), new WeakReference<Method>( javaClassFactoryMethod ) ); 392 } 393 394 return javaClassFactoryMethod; 395 } 396 } 397 398 /** 399 * Gets a flag indicating the Java class of the instance is assignable to all Java classes of all specifications of 400 * the instance. 401 * <p>This method queries an internal cache for a result object to return for the given argument values. If no 402 * cached result object is available, this method queries the super-class for a result object to return and caches 403 * the outcome of that query for use on successive calls.</p> 404 * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the 405 * internal cache with the state of the instance and class loader, should the state of the instance or class loader 406 * change.</p> 407 * 408 * @param classLoader The class loader to get the Java classes from or {@code null}, to get the Java classes from 409 * the platform's bootstrap class loader. 410 * 411 * @return {@code true}, if the Java class of the instance is assignable to all Java classes of all specifications 412 * of the instance; {@code false}, if the Java class of the instance is not assignable to all Java classes of all 413 * specifications of the instance. 414 * 415 * @throws ClassNotFoundException if a Java class is not found. 416 * 417 * @see #getJavaClass(java.lang.ClassLoader) 418 * @see #getJavaClasses(java.lang.ClassLoader) 419 * @see RuntimeModelObjects#clear() 420 */ 421 @Override 422 public boolean isJavaClassAssignable( final ClassLoader classLoader ) throws ClassNotFoundException 423 { 424 ClassLoader classLoaderKey = classLoader; 425 if ( classLoaderKey == null ) 426 { 427 classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY; 428 } 429 430 synchronized ( assignableFlagsByClassLoaderAndInstanceCache ) 431 { 432 Map<String, Boolean> map = assignableFlagsByClassLoaderAndInstanceCache.get( classLoaderKey ); 433 434 if ( map == null ) 435 { 436 map = createMap(); 437 assignableFlagsByClassLoaderAndInstanceCache.put( classLoaderKey, map ); 438 } 439 440 Boolean javaClassAssignable = map.get( this.getIdentifier() ); 441 442 if ( javaClassAssignable == null && !map.containsKey( this.getIdentifier() ) ) 443 { 444 javaClassAssignable = super.isJavaClassAssignable( classLoader ); 445 map.put( this.getIdentifier(), javaClassAssignable ); 446 } 447 448 return javaClassAssignable == null ? false : javaClassAssignable; 449 } 450 } 451 452 /** 453 * Gets the Java proxy class for a given class loader. 454 * <p>This method queries an internal cache for a result object to return for the given argument values. If no 455 * cached result object is available, this method queries the super-class for a result object to return and caches 456 * the outcome of that query for use on successive calls.</p> 457 * <p><b>Note:</b><br/>Method {@code RuntimeModelObjects.clear()} must be used to synchronize the state of the 458 * internal cache with the state of the instance and class loader, should the state of the instance or class loader 459 * change.</p> 460 * 461 * @param classLoader The class loader to get the Java proxy class for. 462 * 463 * @return The Java proxy class for {@code classLoader} or {@code null}, if the instance does not support a Java 464 * proxy class. 465 * 466 * @throws ClassNotFoundException if a Java class is not found. 467 * 468 * @see #getJavaClasses(java.lang.ClassLoader) 469 * @see RuntimeModelObjects#clear() 470 */ 471 @Override 472 public Class<?> getJavaProxyClass( final ClassLoader classLoader ) throws ClassNotFoundException 473 { 474 ClassLoader classLoaderKey = classLoader; 475 if ( classLoaderKey == null ) 476 { 477 classLoaderKey = BOOTSTRAP_CLASSLOADER_KEY; 478 } 479 480 synchronized ( proxyClassesByClassLoaderAndInstanceCache ) 481 { 482 Class<?> javaProxyClass = null; 483 Map<String, Reference<Class<?>>> map = proxyClassesByClassLoaderAndInstanceCache.get( classLoaderKey ); 484 485 if ( map == null ) 486 { 487 map = createMap(); 488 proxyClassesByClassLoaderAndInstanceCache.put( classLoaderKey, map ); 489 } 490 491 final Reference<Class<?>> reference = map.get( this.getIdentifier() ); 492 493 if ( reference != null ) 494 { 495 javaProxyClass = reference.get(); 496 } 497 498 if ( javaProxyClass == null && ( reference != null || !map.containsKey( this.getIdentifier() ) ) ) 499 { 500 javaProxyClass = super.getJavaProxyClass( classLoader ); 501 map.put( this.getIdentifier(), new WeakReference<Class<?>>( javaProxyClass ) ); 502 } 503 504 return javaProxyClass; 505 } 506 } 507 508 // SECTION-END 509 // SECTION-START[RuntimeModelObject] 510 public void gc() 511 { 512 this.gcOrClear( true, false ); 513 } 514 515 public void clear() 516 { 517 this.javaClassFactoryMethodName = null; 518 this.gcOrClear( false, true ); 519 } 520 521 private void gcOrClear( final boolean gc, final boolean clear ) 522 { 523 if ( this.getAuthors() instanceof RuntimeModelObject ) 524 { 525 if ( gc ) 526 { 527 ( (RuntimeModelObject) this.getAuthors() ).gc(); 528 } 529 if ( clear ) 530 { 531 ( (RuntimeModelObject) this.getAuthors() ).clear(); 532 } 533 } 534 if ( this.getDependencies() instanceof RuntimeModelObject ) 535 { 536 if ( gc ) 537 { 538 ( (RuntimeModelObject) this.getDependencies() ).gc(); 539 } 540 if ( clear ) 541 { 542 ( (RuntimeModelObject) this.getDependencies() ).clear(); 543 } 544 } 545 if ( this.getDocumentation() instanceof RuntimeModelObject ) 546 { 547 if ( gc ) 548 { 549 ( (RuntimeModelObject) this.getDocumentation() ).gc(); 550 } 551 if ( clear ) 552 { 553 ( (RuntimeModelObject) this.getDocumentation() ).clear(); 554 } 555 } 556 if ( this.getMessages() instanceof RuntimeModelObject ) 557 { 558 if ( gc ) 559 { 560 ( (RuntimeModelObject) this.getMessages() ).gc(); 561 } 562 if ( clear ) 563 { 564 ( (RuntimeModelObject) this.getMessages() ).clear(); 565 } 566 } 567 if ( this.getProperties() instanceof RuntimeModelObject ) 568 { 569 if ( gc ) 570 { 571 ( (RuntimeModelObject) this.getProperties() ).gc(); 572 } 573 if ( clear ) 574 { 575 ( (RuntimeModelObject) this.getProperties() ).clear(); 576 } 577 } 578 if ( this.getSpecifications() instanceof RuntimeModelObject ) 579 { 580 if ( gc ) 581 { 582 ( (RuntimeModelObject) this.getSpecifications() ).gc(); 583 } 584 if ( clear ) 585 { 586 ( (RuntimeModelObject) this.getSpecifications() ).clear(); 587 } 588 } 589 } 590 591 // SECTION-END 592 // SECTION-START[Constructors] 593 // <editor-fold defaultstate="collapsed" desc=" Generated Constructors "> 594 /** Creates a new {@code RuntimeInstance} instance. */ 595 @javax.annotation.Generated( value = "org.jomc.tools.SourceFileProcessor 1.3", comments = "See http://jomc.sourceforge.net/jomc/1.3/jomc-tools-1.3" ) 596 public RuntimeInstance() 597 { 598 // SECTION-START[Default Constructor] 599 super(); 600 // SECTION-END 601 } 602 // </editor-fold> 603 // SECTION-END 604 // SECTION-START[Dependencies] 605 // SECTION-END 606 // SECTION-START[Properties] 607 // SECTION-END 608 // SECTION-START[Messages] 609 // SECTION-END 610}