Package nexj.core.runtime.sys

Source Code of nexj.core.runtime.sys.SysCounter

// Copyright 2010 NexJ Systems Inc. This software is licensed under the terms of the Eclipse Public License 1.0
package nexj.core.runtime.sys;

import nexj.core.meta.Metaclass;
import nexj.core.meta.Primitive;
import nexj.core.persistence.Query;
import nexj.core.runtime.ActionContext;
import nexj.core.runtime.Instance;
import nexj.core.runtime.InstanceList;
import nexj.core.runtime.InvocationContext;
import nexj.core.runtime.InvocationContextAware;
import nexj.core.runtime.UnitOfWork;
import nexj.core.scripting.Pair;
import nexj.core.scripting.Symbol;
import nexj.core.util.HashTab;
import nexj.core.util.Lifecycle;
import nexj.core.util.Lookup;
import nexj.core.util.UncheckedException;

/**
* Counter implementation.
*/
public class SysCounter implements InvocationContextAware, Lifecycle
{
   // constants

   /**
    * The attributes to read.
    */
   protected final static Pair ATTRIBUTES = Pair.list(Symbol.NAME, Symbol.VALUE,
      Symbol.define("increment"), Symbol.define("cache"));

   // attributes

   /**
    * True if this counter's "next" event is being called.
    */
   protected boolean m_bBusy;

   // associations

   /**
    * The invocation context.
    */
   protected InvocationContext m_context;

   /**
    * The counter name to object map: Counter[String].
    */
   protected final static Lookup s_counterMap = new HashTab();

   // operations

   /**
    * @see nexj.core.runtime.InvocationContextAware#setInvocationContext(nexj.core.runtime.InvocationContext)
    */
   public void setInvocationContext(InvocationContext context)
   {
      m_context = context;
   }

   /**
    * Increments the named counter and returns the new value.
    * next(name)
    */
   public Long next(Metaclass metaclass, String sName, ActionContext actx)
   {
      Counter counter;

      synchronized (s_counterMap)
      {
         counter = (Counter)s_counterMap.get(sName);

         if (counter != null && !counter.isStale())
         {
            return Primitive.createLong(counter.next());
         }
      }

      UnitOfWork uowOld = m_context.beginTransaction(false);
      boolean bCommitted = false;

      try
      {
         InstanceList list = Query.createRead(metaclass, ATTRIBUTES,
            Pair.binary(Symbol.EQ, Symbol.NAME, sName),
            null, -1, 0, true, Query.SEC_NONE, m_context).read();

         if (list.isEmpty())
         {
            throw new UncheckedException("err.runtime.unknownCounter", new Object[]{sName});
         }

         long lValue;

         m_bBusy = true;

         synchronized (s_counterMap)
         {
            counter = (Counter)s_counterMap.get(sName);

            if (counter != null && !counter.isStale())
            {
               return Primitive.createLong(counter.next());
            }

            if (counter == null)
            {
               counter = new Counter();
               s_counterMap.put(sName, counter);
            }

            Instance instance = list.getInstance(0);

            counter.initialize(((Number)instance.getValue("value")).longValue(),
               ((Number)instance.getValue("increment")).longValue(),
               ((Number)instance.getValue("cache")).intValue());

            instance.setValue("value", Primitive.createLong(counter.getLimit()));
            lValue = counter.next();
         }

         m_context.commitAndResume(uowOld);
         bCommitted = true;

         return Primitive.createLong(lValue);
      }
      finally
      {
         if (!bCommitted)
         {
            m_context.rollbackAndResume(uowOld);
         }

         m_bBusy = false;
      }
   }

   /**
    * Clears the cached value of the counter iff the developer has explicitly updated the value attribute.
    * commit()
    */
   public void commit(Instance instance, ActionContext actx)
   {
      if (!m_bBusy)
      {
         s_counterMap.remove((String)instance.getValue("name"));
      }
   }

   /**
    * @see nexj.core.util.Lifecycle#shutdown()
    */
   public void shutdown()
   {
   }

   /**
    * @see nexj.core.util.Lifecycle#startup()
    */
   public void startup() throws Exception
   {
      synchronized (s_counterMap)
      {
         s_counterMap.clear();
      }
   }

   /**
    * @see nexj.core.util.Suspendable#resume()
    */
   public void resume() throws Exception
   {
      synchronized (s_counterMap)
      {
         s_counterMap.clear();
      }
   }

   /**
    * @see nexj.core.util.Suspendable#suspend()
    */
   public void suspend() throws Exception
   {
   }

   // inner classes

   /**
    * The counter state.
    */
   protected static class Counter
   {
      // attributes

      /**
       * Current value.
       */
      protected long m_lValue;

      /**
       * Upper limit.
       */
      protected long m_lLimit;

      /**
       * The value by which to increment the counter.
       */
      protected long m_lIncrement;

      // constructors

      /**
       * Constructs the counter.
       */
      public Counter()
      {
      }

      /**
       * Constructs the counter.
       * @param lValue The counter value.
       * @param lIncrement The counter increment.
       * @param nCache The number of values to cache.
       */
      public Counter(long lValue, long lIncrement, int nCache)
      {
         initialize(lValue, lIncrement, nCache);
      }

      // operations

      /**
       * Initializes the counter.
       * @param lValue The counter value.
       * @param lIncrement The counter increment.
       * @param nCache The number of values to cache.
       */
      public void initialize(long lValue, long lIncrement, int nCache)
      {
         if (lIncrement == 0)
         {
            lIncrement = 1;
         }

         if (nCache <= 0)
         {
            nCache = 1;
         }

         m_lValue = lValue;
         m_lIncrement = lIncrement;
         m_lLimit = m_lValue + lIncrement * nCache;

         if (m_lIncrement > 0 && m_lLimit < m_lIncrement ||
            m_lIncrement < 0 && m_lLimit > m_lIncrement)
         {
            throw new ArithmeticException("Counter overflow");
         }
      }

      /**
       * Increments the counter.
       * @return The new counter value.
       */
      public long next()
      {
         long lValue = m_lValue;

         m_lValue += m_lIncrement;

         return lValue;
      }

      /**
       * @return The counter limit.
       */
      public long getLimit()
      {
         return m_lLimit;
      }

      /**
       * @return True if the counter must be reinitialized.
       */
      public boolean isStale()
      {
         return m_lValue == m_lLimit;
      }
   }
}
TOP

Related Classes of nexj.core.runtime.sys.SysCounter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.