View Javadoc
1 package org.apache.torque.manager; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001-2003 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache Turbine" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * "Apache Turbine", nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>. 55 */ 56 57 import java.lang.ref.WeakReference; 58 import java.util.Arrays; 59 import java.util.List; 60 import java.util.ArrayList; 61 import java.util.Map; 62 import java.util.HashMap; 63 import java.util.Iterator; 64 import java.io.Serializable; 65 import java.io.IOException; 66 import java.io.ObjectInputStream; 67 68 import org.apache.commons.collections.FastArrayList; 69 import org.apache.jcs.JCS; 70 import org.apache.jcs.access.GroupCacheAccess; 71 import org.apache.jcs.access.exception.CacheException; 72 73 import org.apache.torque.Torque; 74 import org.apache.torque.TorqueException; 75 import org.apache.torque.om.ObjectKey; 76 import org.apache.torque.om.Persistent; 77 78 import org.apache.commons.logging.Log; 79 import org.apache.commons.logging.LogFactory; 80 81 /*** 82 * This class contains common functionality of a Manager for 83 * instantiating OM's. 84 * 85 * @author <a href="mailto:jmcnally@collab.net">John McNally</a> 86 * @version $Id: AbstractBaseManager.java,v 1.16 2003/06/20 08:13:47 dlr Exp $ 87 */ 88 public abstract class AbstractBaseManager 89 implements Serializable 90 { 91 /*** the log */ 92 protected static Log log = LogFactory.getLog(AbstractBaseManager.class); 93 94 /*** used to cache the om objects. cache is set by the region property */ 95 protected transient GroupCacheAccess cache; 96 97 /*** method results cache */ 98 protected MethodResultCache mrCache; 99 100 /*** the class that the service will instantiate */ 101 private Class omClass; 102 103 private String className; 104 105 private String region; 106 107 private boolean isNew = true; 108 109 protected Map validFields; 110 protected Map listenersMap = new HashMap(); 111 112 /*** 113 * Get the Class instance 114 * 115 * @return the om class 116 */ 117 protected Class getOMClass() 118 { 119 return omClass; 120 } 121 122 /*** 123 * Set the Class that will be instantiated by this manager 124 * 125 * @param omClass the om class 126 */ 127 protected void setOMClass(Class omClass) 128 { 129 this.omClass = omClass; 130 } 131 132 /*** 133 * Get a fresh instance of an om 134 * 135 * @return an instance of the om class 136 * @throws InstantiationException 137 * @throws IllegalAccessException 138 */ 139 protected Persistent getOMInstance() 140 throws InstantiationException, IllegalAccessException 141 { 142 return (Persistent) omClass.newInstance(); 143 } 144 145 /*** 146 * Get the classname to instantiate for getInstance() 147 * @return value of className. 148 */ 149 public String getClassName() 150 { 151 return className; 152 } 153 154 /*** 155 * Set the classname to instantiate for getInstance() 156 * @param v Value to assign to className. 157 * @throws TorqueException Any exceptions caught during processing will be 158 * rethrown wrapped into a TorqueException. 159 */ 160 public void setClassName(String v) 161 throws TorqueException 162 { 163 this.className = v; 164 165 try 166 { 167 setOMClass(Class.forName(getClassName())); 168 } 169 catch (ClassNotFoundException cnfe) 170 { 171 throw new TorqueException("Could not load " + getClassName()); 172 } 173 } 174 175 176 /*** 177 * Return an instance of an om based on the id 178 * 179 * @param id 180 * @throws TorqueException Any exceptions caught during processing will be 181 * rethrown wrapped into a TorqueException. 182 */ 183 protected Persistent getOMInstance(ObjectKey id) 184 throws TorqueException 185 { 186 return getOMInstance(id, true); 187 } 188 189 /*** 190 * Return an instance of an om based on the id 191 * 192 * @throws TorqueException Any exceptions caught during processing will be 193 * rethrown wrapped into a TorqueException. 194 */ 195 protected Persistent getOMInstance(ObjectKey key, boolean fromCache) 196 throws TorqueException 197 { 198 Persistent om = null; 199 if (fromCache) 200 { 201 om = cacheGet(key); 202 } 203 204 if (om == null) 205 { 206 om = retrieveStoredOM(key); 207 if (fromCache) 208 { 209 putInstanceImpl(om); 210 } 211 } 212 213 return om; 214 } 215 216 protected Persistent cacheGet(Serializable key) 217 { 218 Persistent om = null; 219 if (cache != null) 220 { 221 synchronized (this) 222 { 223 om = (Persistent) cache.get(key); 224 } 225 } 226 return om; 227 } 228 229 /*** 230 * 231 * @throws TorqueException Any exceptions caught during processing will be 232 * rethrown wrapped into a TorqueException. 233 */ 234 protected void clearImpl() 235 throws TorqueException 236 { 237 if (cache != null) 238 { 239 try 240 { 241 cache.remove(); 242 } 243 catch (CacheException ce) 244 { 245 throw new TorqueException( 246 "Could not clear cache due to internal JCS error.", ce); 247 } 248 } 249 } 250 251 /*** 252 * 253 * @param key 254 * @return 255 * @throws TorqueException Any exceptions caught during processing will be 256 * rethrown wrapped into a TorqueException. 257 */ 258 protected Persistent removeInstanceImpl(Serializable key) 259 throws TorqueException 260 { 261 Persistent oldOm = null; 262 if (cache != null) 263 { 264 try 265 { 266 synchronized (this) 267 { 268 oldOm = (Persistent) cache.get(key); 269 cache.remove(key); 270 } 271 } 272 catch (CacheException ce) 273 { 274 throw new TorqueException 275 ("Could not remove from cache due to internal JCS error", 276 ce); 277 } 278 } 279 return oldOm; 280 } 281 282 /*** 283 * 284 * @param om 285 * @return 286 * @throws TorqueException Any exceptions caught during processing will be 287 * rethrown wrapped into a TorqueException. 288 */ 289 protected Persistent putInstanceImpl(Persistent om) 290 throws TorqueException 291 { 292 ObjectKey key = om.getPrimaryKey(); 293 return putInstanceImpl(key, om); 294 } 295 296 /*** 297 * 298 * @param key 299 * @param om 300 * @return 301 * @throws TorqueException Any exceptions caught during processing will be 302 * rethrown wrapped into a TorqueException. 303 */ 304 protected Persistent putInstanceImpl(Serializable key, Persistent om) 305 throws TorqueException 306 { 307 if (getOMClass() != null && !getOMClass().isInstance(om)) 308 { 309 throw new TorqueException(om + "; class=" + om.getClass().getName() 310 + "; id=" + om.getPrimaryKey() + " cannot be cached with " 311 + getOMClass().getName() + " objects"); 312 } 313 314 Persistent oldOm = null; 315 if (cache != null) 316 { 317 try 318 { 319 synchronized (this) 320 { 321 oldOm = (Persistent) cache.get(key); 322 cache.put(key, om); 323 } 324 } 325 catch (CacheException ce) 326 { 327 throw new TorqueException 328 ("Could not cache due to internal JCS error", ce); 329 } 330 } 331 return oldOm; 332 } 333 334 /*** 335 * 336 * @param id 337 * @return 338 * @throws TorqueException Any exceptions caught during processing will be 339 * rethrown wrapped into a TorqueException. 340 */ 341 protected abstract Persistent retrieveStoredOM(ObjectKey id) 342 throws TorqueException; 343 344 /*** 345 * Gets a list of om's based on id's. 346 * 347 * @param ids a <code>ObjectKey[]</code> value 348 * @return a <code>List</code> value 349 * @throws TorqueException Any exceptions caught during processing will be 350 * rethrown wrapped into a TorqueException. 351 */ 352 protected List getOMs(ObjectKey[] ids) 353 throws TorqueException 354 { 355 return getOMs(Arrays.asList(ids)); 356 } 357 358 /*** 359 * Gets a list of om's based on id's. 360 * 361 * @param ids a <code>List</code> of <code>ObjectKey</code>'s 362 * @return a <code>List</code> value 363 * @throws TorqueException Any exceptions caught during processing will be 364 * rethrown wrapped into a TorqueException. 365 */ 366 protected List getOMs(List ids) 367 throws TorqueException 368 { 369 return getOMs(ids, true); 370 } 371 372 /*** 373 * Gets a list of om's based on id's. 374 * 375 * @param ids a <code>List</code> of <code>ObjectKey</code>'s 376 * @return a <code>List</code> value 377 * @throws TorqueException Any exceptions caught during processing will be 378 * rethrown wrapped into a TorqueException. 379 */ 380 protected List getOMs(List ids, boolean fromCache) 381 throws TorqueException 382 { 383 List oms = null; 384 if (ids != null && ids.size() > 0) 385 { 386 // start a new list where we will replace the id's with om's 387 oms = new ArrayList(ids); 388 List newIds = new ArrayList(ids.size()); 389 for (int i = 0; i < ids.size(); i++) 390 { 391 ObjectKey key = (ObjectKey) ids.get(i); 392 Persistent om = null; 393 if (fromCache) 394 { 395 om = cacheGet(key); 396 } 397 if (om == null) 398 { 399 newIds.add(key); 400 } 401 else 402 { 403 oms.set(i, om); 404 } 405 } 406 407 if (newIds.size() > 0) 408 { 409 List newOms = retrieveStoredOMs(newIds); 410 for (int i = 0; i < oms.size(); i++) 411 { 412 if (oms.get(i) instanceof ObjectKey) 413 { 414 for (int j = newOms.size() - 1; j >= 0; j--) 415 { 416 Persistent om = (Persistent) newOms.get(j); 417 if (om.getPrimaryKey().equals(oms.get(i))) 418 { 419 // replace the id with the om and add the om 420 // to the cache 421 oms.set(i, om); 422 newOms.remove(j); 423 if (fromCache) 424 { 425 putInstanceImpl(om); 426 } 427 break; 428 } 429 } 430 } 431 } 432 } 433 } 434 return oms; 435 } 436 437 /*** 438 * 439 * @param ids 440 * @return 441 * @throws TorqueException Any exceptions caught during processing will be 442 * rethrown wrapped into a TorqueException. 443 */ 444 protected abstract List retrieveStoredOMs(List ids) 445 throws TorqueException; 446 447 /*** 448 * Get the value of region. 449 * 450 * @return value of region. 451 */ 452 public String getRegion() 453 { 454 return region; 455 } 456 457 /*** 458 * Set the value of region. 459 * 460 * @param v Value to assign to region. 461 * @throws TorqueException Any exceptions caught during processing will be 462 * rethrown wrapped into a TorqueException. 463 */ 464 public void setRegion(String v) 465 throws TorqueException 466 { 467 this.region = v; 468 try 469 { 470 if (Torque.getConfiguration().getBoolean(Torque.CACHE_KEY)) 471 { 472 cache = JCS.getInstance(getRegion()); 473 mrCache = new MethodResultCache(cache); 474 } 475 else 476 { 477 mrCache = new NoOpMethodResultCache(cache); 478 } 479 } 480 catch (Exception e) 481 { 482 throw new TorqueException("Cache could not be initialized", e); 483 } 484 if (cache == null) 485 { 486 log.info("Cache could not be initialized for region: " + v); 487 } 488 } 489 490 /*** 491 * @return The cache instance. 492 */ 493 public MethodResultCache getMethodResultCache() 494 { 495 if (isNew) 496 { 497 synchronized (this) 498 { 499 if (isNew) 500 { 501 registerAsListener(); 502 isNew = false; 503 } 504 } 505 } 506 return mrCache; 507 } 508 509 /*** 510 * NoOp version. Managers should override this method to notify other 511 * managers that they are interested in CacheEvents. 512 */ 513 protected void registerAsListener() 514 { 515 } 516 517 /*** 518 * 519 * @param listener A new listener for cache events. 520 */ 521 public void addCacheListenerImpl(CacheListener listener) 522 { 523 List keys = listener.getInterestedFields(); 524 Iterator i = keys.iterator(); 525 while (i.hasNext()) 526 { 527 String key = (String) i.next(); 528 // Peer.column names are the fields 529 if (validFields != null && validFields.containsKey(key)) 530 { 531 List listeners = (List) listenersMap.get(key); 532 if (listeners == null) 533 { 534 listeners = createSubsetList(key); 535 } 536 537 boolean isNew = true; 538 Iterator j = listeners.iterator(); 539 while (j.hasNext()) 540 { 541 Object listener2 = 542 ((WeakReference) j.next()).get(); 543 if (listener2 == null) 544 { 545 // do a little cleanup while checking for dupes 546 // not thread-safe, not likely to be many nulls 547 // but should revisit 548 //j.remove(); 549 } 550 else if (listener2 == listener) 551 { 552 isNew = false; 553 break; 554 } 555 } 556 if (isNew) 557 { 558 listeners.add(new WeakReference(listener)); 559 } 560 } 561 } 562 } 563 564 /*** 565 * 566 * @param key 567 * @return A subset of the list identified by <code>key</code>. 568 */ 569 private synchronized List createSubsetList(String key) 570 { 571 FastArrayList list = null; 572 if (listenersMap.containsKey(key)) 573 { 574 list = (FastArrayList) listenersMap.get(key); 575 } 576 else 577 { 578 list = new FastArrayList(); 579 list.setFast(true); 580 listenersMap.put(key, list); 581 } 582 return list; 583 } 584 585 /*** 586 * 587 * @param listeners 588 * @param oldOm 589 * @param om 590 */ 591 protected void notifyListeners(List listeners, 592 Persistent oldOm, Persistent om) 593 { 594 if (listeners != null) 595 { 596 synchronized (listeners) 597 { 598 Iterator i = listeners.iterator(); 599 while (i.hasNext()) 600 { 601 CacheListener listener = (CacheListener) 602 ((WeakReference) i.next()).get(); 603 if (listener == null) 604 { 605 // remove reference as its object was cleared 606 i.remove(); 607 } 608 else 609 { 610 if (oldOm == null) 611 { 612 // object was added 613 listener.addedObject(om); 614 } 615 else 616 { 617 // object was refreshed 618 listener.refreshedObject(om); 619 } 620 } 621 } 622 } 623 } 624 } 625 626 627 /*** 628 * helper methods for the Serializable interface 629 * 630 * @param out 631 * @throws IOException 632 */ 633 private void writeObject(java.io.ObjectOutputStream out) 634 throws IOException 635 { 636 out.defaultWriteObject(); 637 } 638 639 /*** 640 * Helper methods for the <code>Serializable</code> interface. 641 * 642 * @param in The stream to read a <code>Serializable</code> from. 643 * @throws IOException 644 * @throws ClassNotFoundException 645 */ 646 private void readObject(ObjectInputStream in) 647 throws IOException, ClassNotFoundException 648 { 649 in.defaultReadObject(); 650 // initialize the cache 651 try 652 { 653 if (region != null) 654 { 655 setRegion(region); 656 } 657 } 658 catch (Exception e) 659 { 660 log.error("Cache could not be initialized for region '" 661 + region + "' after deserialization"); 662 } 663 } 664 }

This page was automatically generated by Maven