jakarta-jcs-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From asm...@apache.org
Subject cvs commit: jakarta-turbine-jcs/src/java/org/apache/jcs/utils/access JCSWorkerHelper.java JCSWorker.java AbstractJCSWorkerHelper.java
Date Sat, 11 Jun 2005 00:30:24 GMT
asmuts      2005/06/10 17:30:24

  Added:       src/java/org/apache/jcs/utils/access JCSWorkerHelper.java
                        JCSWorker.java AbstractJCSWorkerHelper.java
  Log:
  moved savo's caching workers into the main tree.  we need some unit tests for this.
  
  Revision  Changes    Path
  1.1                  jakarta-turbine-jcs/src/java/org/apache/jcs/utils/access/JCSWorkerHelper.java
  
  Index: JCSWorkerHelper.java
  ===================================================================
  package org.apache.jcs.utils.access;
  
  /*
   * Copyright 2002-2004 The Apache Software Foundation.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License") you may not
   * use this file except in compliance with the License. You may obtain a copy of
   * the License at
   * 
   * http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   * License for the specific language governing permissions and limitations under
   * the License.
   */
  
  /**
   * Interface for doing a piece of work which is expected to be cached. This is
   * ment to be used in conjunction with JCSWorker. Implement doWork() to return
   * the work being done. isFinished() should return false until setFinished(true)
   * is called, after which time it should return true.
   * 
   * @author tsavo
   */
  public interface JCSWorkerHelper
  {
      /**
       * Tells us weather or not the work has been completed. This will be called
       * automatically by JCSWorker. You should not call it yourself.
       * 
       * @return True if the work has allready been done, otherwise false.
       */
      public boolean isFinished();
  
      /**
       * Sets weather or not the work has been done.
       * 
       * @param isFinished
       *            True if the work has allready been done, otherwise false.
       */
      public void setFinished( boolean isFinished );
  
      /**
       * The method to implement to do the work that should be cached. JCSWorker
       * will call this itself! You should not call this directly.
       * 
       * @return The result of doing the work to be cached.
       * @throws Exception
       *             If anything goes wrong while doing the work, an Exception
       *             should be thrown.
       */
      public Object doWork()
          throws Exception;
  }
  
  
  
  1.1                  jakarta-turbine-jcs/src/java/org/apache/jcs/utils/access/JCSWorker.java
  
  Index: JCSWorker.java
  ===================================================================
  package org.apache.jcs.utils.access;
  
  /*
   * Copyright 2002-2004 The Apache Software Foundation.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License") you may not
   * use this file except in compliance with the License. You may obtain a copy of
   * the License at
   * 
   * http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   * License for the specific language governing permissions and limitations under
   * the License.
   */
  
  import java.io.Serializable;
  import java.util.HashMap;
  import java.util.Map;
  
  import org.apache.commons.logging.Log;
  import org.apache.commons.logging.LogFactory;
  import org.apache.jcs.JCS;
  import org.apache.jcs.access.exception.CacheException;
  
  
  /**
   * Utility class to encapsulate doing a piece of work, and caching the results
   * in JCS. Simply construct this class with the region name for the Cache and
   * keep a static reference to it instead of the JCS itself. Then make a new
   * org.apache.jcs.utils.access.AbstractJCSWorkerHelper and implement Object
   * doWork() and do the work in there, returning the object to be cached. Then
   * call .getResult() with the key and the AbstractJCSWorkerHelper to get the
   * result of the work. If the object isn't allready in the Cache,
   * AbstractJCSWorkerHelper.doWork() will get called, and the result will be put
   * into the cache. If the object is allready in cache, the cached result will be
   * returned instead.
   * <p>
   * As an added bonus, multiple JCSWorkers with the same region, and key won't do
   * the work multiple times: The first JCSWorker to get started will do the work,
   * and all subsequent workers with the same region, group, and key will wait on
   * the first one and use his resulting work instead of doing the work
   * themselves.
   * 
   * This is ideal when the work being done is a query to the database where the
   * results may take time to be retrieved.
   * 
   * For example: <br>
   * 
   * <code>
   *    public static JCSWorker cachingWorker = new JCSWorker("example region");<br>
   * 		public Object getSomething(Serializable aKey){<br>
   *      JCSWorkerHelper helper = new AbstractJCSWorkerHelper(){<br>
   *        public Object doWork(){<br>
   *          // Do some (DB?) work here which results in a list <br>
   *          // This only happens if the cache dosn't have a item in this region for aKey
<br>
   *          // Note this is especially useful with Hibernate, which will cache indiviual
<br>
   *          // Objects, but not entire query result sets. <br>
   *          List results = query.list(); <br>
   *          // Whatever we return here get's cached with aKey, and future calls to <br>
   *          // getResult() on a CachedWorker with the same region and key will return that
instead. <br>
   *          return results; <br>
   *      };<br>
   *      List result = worker.getResult(aKey, helper);<br>
   *    }
   * </code>
   * 
   * This is essentially the same as doing: <code>
   *  JCS jcs = JCS.getInstance("exampleregion");<br>
   *  List results = (List) jcs.get(aKey);<br>
   *  if(results != null){ //do the work here<br>
   *    results = query.list(); jcs.put(aKey, results);<br>
   *  }<br>
   * </code>
   * 
   * But has the added benifit of the work-load sharing; under normal
   * circumstances if multiple threads all tried to do the same query at the same
   * time, the same query would happen multiple times on the database, and the
   * resulting object would get put into JCS multiple times.
   * 
   * @author Travis Savo
   */
  public class JCSWorker
  {
      private static final Log logger = LogFactory.getLog( JCSWorker.class );
  
      private JCS cache;
  
      /**
       * Map to hold who's doing work presently.
       */
      private static volatile Map map = new HashMap();
  
      /**
       * Region for the JCS cache.
       */
      private String region;
  
      /**
       * Constructor which takes a region for the JCS cache.
       * 
       * @param aName
       *            The Region to use for the JCS cache.
       * @param aKey
       *            The key to store the result under.
       * @param aGroup
       *            The group to store the result under.
       */
      public JCSWorker( final String aRegion )
      {
          region = aRegion;
          try
          {
              cache = JCS.getInstance( aRegion );
          }
          catch ( CacheException e )
          {
              throw new RuntimeException( e.getMessage() );
          }
      }
  
      /**
       * Getter for the region of the JCS Cache.
       * 
       * @return The JCS region in which the result will be cached.
       */
      public String getRegion()
      {
          return region;
      }
  
      /**
       * Gets the cached result for this region/key OR does the work and caches
       * the result, returning the result. If the result has not been cached yet,
       * this calls doWork() on the JCSWorkerHelper to do the work and cache the
       * result.
       * 
       * This is also an opertunity to do any post processing of the result in
       * your CachedWorker implementation.
       * 
       * @param aKey
       *            The key to get/put with on the Cache.
       * @param aWorker
       *            The JCSWorkerHelper implementing Object doWork(). This gets
       *            called if the cache get misses, and the result is put into
       *            cache.
       * @return The result of doing the work, or the cached result.
       * @throws Exception
       *             Throws an exception if anything goes wrong while doing the
       *             work.
       */
      public Object getResult( Serializable aKey, JCSWorkerHelper aWorker )
          throws Exception
      {
          return run( aKey, null, aWorker );
      }
  
      /**
       * Gets the cached result for this region/key OR does the work and caches
       * the result, returning the result. If the result has not been cached yet,
       * this calls doWork() on the JCSWorkerHelper to do the work and cache the
       * result.
       * 
       * This is also an opertunity to do any post processing of the result in
       * your CachedWorker implementation.
       * 
       * @param aKey
       *            The key to get/put with on the Cache.
       * @param aGroup
       *            The cache group to put the result in.
       * @param aWorker
       *            The JCSWorkerHelper implementing Object doWork(). This gets
       *            called if the cache get misses, and the result is put into
       *            cache.
       * @return The result of doing the work, or the cached result.
       * @throws Exception
       *             Throws an exception if anything goes wrong while doing the
       *             work.
       */
      public Object getResult( Serializable aKey, String aGroup, JCSWorkerHelper aWorker )
          throws Exception
      {
          return run( aKey, aGroup, aWorker );
      }
  
      /**
       * Try and get the object from the cache, and if it's not there, do the work
       * and cache it. This also ensures that only one CachedWorker is doing the
       * work and subsequent calls to a CachedWorker with identical
       * region/key/group will wait on the results of this call. It will call the
       * JCSWorkerHelper.doWork() if the cache misses, and will put the result.
       * 
       * @return Either the result of doing the work, or the cached result.
       * @throws Exception
       *             If something goes wrong while doing the work, throw an
       *             exception.
       */
      private Object run( Serializable aKey, String aGroup, JCSWorkerHelper aHelper )
          throws Exception
      {
          Object result = null;
          long start = 0;
          long dbTime = 0;
          JCSWorkerHelper helper = null;
  
          synchronized ( map )
          {
              //Check to see if we allready have a thread doing this work.
              helper = (JCSWorkerHelper) map.get( getRegion() + aKey );
              if ( helper == null )
              {
                  //If not, add ourselves as the Worker so
                  //calls in another thread will use this worker's result
                  map.put( getRegion() + aKey, aHelper );
              }
          }
          if ( helper != null )
          {
              synchronized ( helper )
              {
                  if ( logger.isDebugEnabled() )
                  {
                      logger.debug( "Found a worker allready doing this work (" + getRegion()
+ ":" + aKey + ")." );
                  }
                  if ( !helper.isFinished() )
                  {
                      helper.wait();
                  }
                  if ( logger.isDebugEnabled() )
                  {
                      logger.debug( "Another thread finished our work for us. Using thoes
results instead. ("
                          + getRegion() + ":" + aKey + ")." );
                  }
              }
          }
          //Do the work
          try
          {
              if ( logger.isDebugEnabled() )
              {
                  logger.debug( getRegion() + " is doing the work." );
              }
              result = null;
  
              //Try to get the item from the cache
              if ( aGroup != null )
              {
                  result = cache.getFromGroup( aKey, aGroup );
              }
              else
              {
                  result = cache.get( aKey );
              }
              //If the cache dosn't have it, do the work.
              if ( result == null )
              {
                  result = aHelper.doWork();
                  if ( logger.isDebugEnabled() )
                  {
                      logger.debug( "Work Done, caching: key:" + aKey + ", group:" + aGroup
+ ", result:" + result + "." );
                  }
                  //Stick the result of the work in the cache.
                  if ( aGroup != null )
                  {
                      cache.putInGroup( aKey, aGroup, result );
                  }
                  else
                  {
                      cache.put( aKey, result );
                  }
              }
              //return the result
              return result;
          }
          finally
          {
              if ( logger.isDebugEnabled() )
              {
                  logger.debug( getRegion() + ":" + aKey + " entered finally." );
              }
              synchronized ( map )
              {
                  //Remove ourselves as the worker.
                  if ( helper == null )
                  {
                      map.remove( getRegion() + aKey );
                  }
                  synchronized ( this )
                  {
                      aHelper.setFinished( true );
                      //Wake everyone waiting on us
                      notifyAll();
                  }
              }
          }
      }
  }
  
  
  1.1                  jakarta-turbine-jcs/src/java/org/apache/jcs/utils/access/AbstractJCSWorkerHelper.java
  
  Index: AbstractJCSWorkerHelper.java
  ===================================================================
  package org.apache.jcs.utils.access;
  
  /*
   * Copyright 2002-2004 The Apache Software Foundation.
   * 
   * Licensed under the Apache License, Version 2.0 (the "License") you may not
   * use this file except in compliance with the License. You may obtain a copy of
   * the License at
   * 
   * http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   * License for the specific language governing permissions and limitations under
   * the License.
   */
  
  /**
   * @author tsavo
   *
   */
  public abstract class AbstractJCSWorkerHelper implements JCSWorkerHelper {
  	private boolean finished = false;
  	/**
  	 * 
  	 */
  	public AbstractJCSWorkerHelper() {
  		super();
  		// TODO Auto-generated constructor stub
  	}
  
  	public boolean isFinished(){
  		return finished;
  	}
  	
  	public void setFinished(boolean isFinished){
  		finished = isFinished;
  	}
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: jcs-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: jcs-dev-help@jakarta.apache.org


Mime
View raw message