/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.mx.interceptor;

import javax.management.Attribute;
import javax.management.Descriptor;
import javax.management.MBeanException;

import org.jboss.mx.modelmbean.ModelMBeanConstants;
import org.jboss.mx.modelmbean.ModelMBeanInvoker;
import org.jboss.mx.server.Invocation;
import org.jboss.mx.server.InvocationException;


/** This interceptor handles the ModelMBean attribute caching and setter
 * and getter dispatches.
 *
 * @author  <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
 * @author Scott.Stark@jboss.org
 * @version $Revision: 1.6.2.4 $
 */
public class ModelMBeanAttributeInterceptor
      extends AbstractInterceptor
      implements ModelMBeanConstants
{

   // Attributes ----------------------------------------------------
   
   // Constructors --------------------------------------------------
   
   public ModelMBeanAttributeInterceptor()
   {
      super("ModelMBean Attribute Interceptor");
   }

   
   // Public --------------------------------------------------------
   
   public Object invoke(Invocation invocation) throws InvocationException
   {
      // get the attribute's descriptor
      Descriptor d    = invocation.getDescriptor();
      
      // check the invocation access point: setAttribute()   
      if (invocation.getType().equals(Invocation.OP_SETATTRIBUTE))
      {
         // setAttribute always contains one arg
         Object value    = invocation.getArgs() [0];
         
         // store the old value of this attribute for notification
         Object oldValue = d.getFieldValue(VALUE);

         // check if the attribute maps to a setter
         String setMethod = (String)d.getFieldValue(SET_METHOD);
       
         if (setMethod != null)
         {
            // if setter was found, invoke the corresponding setter operation
            invocation.dispatch();
         }

         d.setField(VALUE, value);
         d.setField(LAST_UPDATED_TIME_STAMP, "" + System.currentTimeMillis() / 1000);
         invocation.setDescriptor(d);
         
         // send notification
         try
         {
            ModelMBeanInvoker invoker = (ModelMBeanInvoker) invocation.getInvoker();
            invoker.sendAttributeChangeNotification(
               new Attribute(invocation.getName(), oldValue),
               new Attribute(invocation.getName(), value)
            );         
         }
         catch (MBeanException e)
         {
            throw new InvocationException(e, "attribute change notification error");
         }
      }
         
      else if (invocation.getType().equals(Invocation.OP_GETATTRIBUTE))
      {   
         // get the attribute's descriptor
         String getMethod = (String)d.getFieldValue(GET_METHOD);
         
         if (getMethod != null)
         {
            String timeLimit = (String)d.getFieldValue(CURRENCY_TIME_LIMIT);
            long limit = (timeLimit == null) ? 0 : Long.parseLong(timeLimit);

            if (limit == -1)
               return d.getFieldValue(VALUE);
  
            // if >0 caching is enabled
            if (limit > 0)
            {
               String timeStamp = (String)d.getFieldValue(LAST_UPDATED_TIME_STAMP);
               long lastUpdate = (timeStamp == null) ? 0 : Long.parseLong(timeStamp);
           
               // if the value hasn't gone stale, return from the descriptor
               if (System.currentTimeMillis() < lastUpdate * 1000 + limit * 1000)
                  return d.getFieldValue(VALUE);
            }

            // we got here means either stale value in descriptior, or zero time limit
            Object value = invocation.dispatch();            
            
            // update the descriptor
            d.setField(VALUE, value);
            d.setField(LAST_UPDATED_TIME_STAMP, "" + System.currentTimeMillis() / 1000);
            
            invocation.setDescriptor(d);
         }
         else
         {
            // There is no instance accessor so check for a default value
            Object defaultValue = d.getFieldValue(DEFAULT);
            String timeStamp = (String)d.getFieldValue(LAST_UPDATED_TIME_STAMP);
            if( defaultValue != null && timeStamp == null )
            {
               // update the descriptor
               d.setField(VALUE, defaultValue);
               d.setField(LAST_UPDATED_TIME_STAMP, "" + System.currentTimeMillis() / 1000);
               invocation.setDescriptor(d);
            }
         }
      }

      return d.getFieldValue(VALUE);
      
   }
   
}




