/*
 * 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.remoting;

import java.util.ArrayList;
import java.util.List;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.ObjectName;
import org.jboss.remoting.InvocationRequest;
import org.jboss.remoting.InvokerCallbackHandler;
import org.jboss.remoting.ServerInvocationHandler;
import org.jboss.remoting.ServerInvocationHandler;
import org.jboss.remoting.ServerInvoker;
import org.jboss.remoting.transport.Connector;
import java.util.Iterator;



/**
 * ServerInterceptorChain.java
 *
 *
 * Created: Fri May  2 10:36:51 2003
 *
 * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
 * @version 1.0
 *
 * @jmx.mbean description="ServerInvocationHandler that represents a chain of ServerInterceptors"
 *
 * @jboss.xmbean
 */
public class ServerInterceptorChain
   implements MBeanRegistration, ServerInvocationHandler
{

   private MBeanServer server;

   private Connector connector;
   private ObjectName connectorName;
   private String subsystem;
   private List interceptorNames;
   private List interceptors;

   public ServerInterceptorChain()
   {

   } // ServerInterceptorChain constructor


   /**
    * Get the Connector value.
    * @return the Connector value.
    * not managed
    */
   public Connector getConnector()
   {
      return connector;
   }

   /**
    * Set the Connector value.
    * @param newConnector The new Connector value.
    * not managed
    */
   public void setConnector(Connector newConnector)
   {
      this.connector = newConnector;
   }


   /**
    * Get the ConnectorName value.
    * @return the ConnectorName value.
    *
    * @jmx.managed-attribute description="Object name of the Connector we register with"
    *      type="ObjectName"
    *      access="read-write"
    */
   public ObjectName getConnectorName()
   {
      return connectorName;
   }

   /**
    * Set the ConnectorName value.
    * @param newConnectorName The new ConnectorName value.
    *
    * @jmx.managed-attribute
    */
   public void setConnectorName(ObjectName newConnectorName)
   {
      this.connectorName = newConnectorName;
   }


   /**
    * Get the Subsystem value.
    * @return the Subsystem value.
    * @jmx.managed-attribute description="Name of the subsystem we work for"
    *      type="String"
    *      access="read-write"
    */
   public String getSubsystem()
   {
      return subsystem;
   }

   /**
    * Set the Subsystem value.
    * @param newSubsystem The new Subsystem value.
    *
    * @jmx.managed-attribute
    */
   public void setSubsystem(String newSubsystem)
   {
      this.subsystem = newSubsystem;
   }


   /**
    * Get the Interceptors value.
    * @return the Interceptors value.
    * not managed
    */
   public List getInterceptors()
   {
      return interceptors;
   }

   /**
    * Set the Interceptors value.
    * @param newInterceptors The new Interceptors value.
    * not managed
    */
   public void setInterceptors(List newInterceptors)
   {
      this.interceptors = newInterceptors;
   }


   /**
    * Get the InterceptorName value.
    * @return the InterceptorName value.
    * @jmx.managed-attribute description="List of object names of the ServerInterceptors we delegate to"
    *      type="List"
    *      access="read-write"
    */
   public List getInterceptorNames()
   {
      return interceptorNames;
   }

   /**
    * Set the InterceptorName value.
    * @param newInterceptorName The new InterceptorName value.
    *
    * @jmx.managed-attribute
    */
   public void setInterceptorNames(List newInterceptorNames)
   {
      this.interceptorNames = newInterceptorNames;
   }


   // Implementation of javax.management.MBeanRegistration

   /**
    * The <code>preRegister</code> method
    *
    * @param MBeanServer a <code>MBeanServer</code> value
    * @param objectName an <code>ObjectName</code> value
    * @return an <code>ObjectName</code> value
    * @exception Exception if an error occurs
    */
   public ObjectName preRegister(MBeanServer server, ObjectName objectName) throws Exception
   {
      this.server = server;
      return objectName;
   }

   /**
    * The <code>postRegister</code> method
    *
    */
   public void postRegister(Boolean success)
   {

   }

   /**
    * The <code>preDeregister</code> method
    *
    * @exception Exception if an error occurs
    */
   public void preDeregister() throws Exception
   {

   }

   /**
    * The <code>postDeregister</code> method
    *
    */
   public void postDeregister()
   {

   }

   //JBoss lifecycle methods
   /**
    * The <code>start</code> method
    *
    * @exception Exception if an error occurs
    *
    * @jmx.managed-operation description="JBoss lifecycle method to set up the interceptor chain from the list of interceptor object names"
    */
   public void start() throws Exception
   {
      List interceptors = new ArrayList();
      for (Iterator i = interceptorNames.iterator(); i.hasNext(); )
      {
         ObjectName iname = (ObjectName)i.next();
         ServerInterceptor si = (ServerInterceptor)server.getAttribute(iname, "Instance");
         interceptors.add(si);
      } // end of for ()
      this.interceptors = interceptors;

      //register with connector
      if (connector != null)
      {
         connector.addInvocationHandler(subsystem, this);
      } // end of if ()
      else
      {
         server.invoke(connectorName,
                       "addInvocationHandler",
                       new Object[] {subsystem, this},
                       new String[] {String.class.getName(), ServerInvocationHandler.class.getName()});
      } // end of else


   }

   /**
    * The <code>stop</code> method
    *
    * @exception Exception if an error occurs
    *
    * @jmx.managed-operation description="JBoss lifecycle method to tear down the list of interceptors"
    */
   public void stop() throws Exception
   {
      //register with connector
      if (connector != null)
      {
         connector.removeInvocationHandler(subsystem);
      } // end of if ()
      else
      {
         server.invoke(connectorName,
                       "removeInvocationHandler",
                       new Object[] {subsystem},
                       new String[] {String.class.getName()});
      } // end of else
      interceptors.clear();//???????
   }


   // Implementation of org.jboss.remoting.ServerInvocationHandler

   /**
    * The <code>addListener</code> method
    *
    * @param invokerCallbackHandler an <code>InvokerCallbackHandler</code> value
    */
   public void addListener(InvokerCallbackHandler invokerCallbackHandler)
   {

   }

   /**
    * The <code>removeListener</code> method
    *
    * @param invokerCallbackHandler an <code>InvokerCallbackHandler</code> value
    */
   public void removeListener(InvokerCallbackHandler invokerCallbackHandler)
   {

   }

   /**
    * The <code>setMBeanServer</code> method
    *
    * @param MBeanServer a <code>MBeanServer</code> value
    */
   public void setMBeanServer(MBeanServer MBeanServer)
   {

   }

   /**
    * The <code>invoke</code> method
    *
    * @param invocationRequest an <code>InvocationRequest</code> value
    * @return an <code>Object</code> value
    * @exception Throwable if an error occurs
    */
   public Object invoke(InvocationRequest invocation) throws Throwable
   {
      InterceptorIterator iterator = new InterceptorIterator(interceptors.iterator(), invocation);
      return iterator.invokeNext();
   }

   /**
    * The <code>setInvoker</code> method
    *
    * @param serverInvoker a <code>ServerInvoker</code> value
    */
   public void setInvoker(ServerInvoker serverInvoker)
   {

   }

    /**
     * called to destroy the handler
     */
    public void destroy() {

    }

   public static class InterceptorIterator
   {
      private final Iterator iterator;
      private final InvocationRequest invocation;

      public InterceptorIterator(final Iterator iterator, final InvocationRequest invocation)
      {
         this.iterator = iterator;
         this.invocation = invocation;
      }

      public Object invokeNext() throws Throwable
      {
         return ((ServerInterceptor)iterator.next()).invoke(this, invocation);
      }

   }

} // ServerInterceptorChain
