Package org.jboss.dependency.plugins

Source Code of org.jboss.dependency.plugins.AbstractController

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

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jboss.dependency.spi.Controller;
import org.jboss.dependency.spi.ControllerContext;
import org.jboss.dependency.spi.ControllerMode;
import org.jboss.dependency.spi.ControllerState;
import org.jboss.dependency.spi.DependencyInfo;
import org.jboss.dependency.spi.DependencyItem;
import org.jboss.util.CollectionsFactory;
import org.jboss.util.JBossObject;

/**
* Abstract controller.
*
* @author <a href="adrian@jboss.com">Adrian Brock</a>
* @version $Revision: 1.10 $
*/
public class AbstractController extends JBossObject implements Controller
{
   /** The states in order List<ControllerState> */
   protected List states = CollectionsFactory.createCopyOnWriteList();
  
   /** All contexts by name Map<Object, ControllerContext> */
   protected Map allContexts = CollectionsFactory.createConcurrentReaderMap();
  
   /** The contexts by state Map<ControllerState, Set<ControllerContext>> */
   protected Map contextsByState = CollectionsFactory.createConcurrentReaderMap();
  
   /** The error contexts Set<ControllerContext> */
   protected Set errorContexts = CollectionsFactory.createCopyOnWriteSet();

   /** The contexts that are currently being installed */
   protected Set installing = CollectionsFactory.createCopyOnWriteSet();
  
   /** Whether an on demand context has been enabled */
   protected boolean onDemandEnabled = true;
  
   /**
    * Create an abstract controller
    *
    * @throws Exception for any error
    */
   public AbstractController() throws Exception
   {
      addState(ControllerState.NOT_INSTALLED, null);
      addState(ControllerState.DESCRIBED, null);
      addState(ControllerState.INSTANTIATED, null);
      addState(ControllerState.CONFIGURED, null);
      addState(ControllerState.CREATE, null);
      addState(ControllerState.START, null);
      addState(ControllerState.INSTALLED, null);
   }

   public void addState(ControllerState state, ControllerState before)
   {
      if (before == null)
      {
         states.add(state);
      }
      else
      {
         int index = states.indexOf(before);
         if (index == -1)
            throw new IllegalStateException(before + " is not a state in the controller.");
         states.add(index, state);
      }
     
      contextsByState.put(state, CollectionsFactory.createCopyOnWriteSet());
   }

   public synchronized ControllerContext getContext(Object name, ControllerState state)
   {
      if (name == null)
         throw new IllegalArgumentException("Null name");
      ControllerContext result = (ControllerContext) allContexts.get(name);
      if (result != null && state != null)
      {
         int required = states.indexOf(state);
         if (required == -1)
            throw new IllegalArgumentException("Unknown state " + state + " states=" + states);
         int current = states.indexOf(result.getState());
         if (current < required)
            return null;
      }
      return result;
   }

   public ControllerContext getInstalledContext(Object name)
   {
      return getContext(name, ControllerState.INSTALLED);
   }

   public synchronized Set getNotInstalled()
   {
      Set result = new HashSet(errorContexts);
      for (int i = 0; ControllerState.INSTALLED.equals(states.get(i)) == false; ++i)
      {
         Set stateContexts = (Set) contextsByState.get(states.get(i));
         result.addAll(stateContexts);
      }
      errorContexts.clear();
      return result;
   }

   public List getStates()
   {
      return states;
   }

   public synchronized void install(ControllerContext context) throws Throwable
   {
      boolean trace = log.isTraceEnabled();
     
      if (context == null)
         throw new IllegalArgumentException("Null context");
     
      Object name = context.getName();
      if (name == null)
         throw new IllegalArgumentException("Null name " + context.toShortString());
     
      if (allContexts.get(name) != null)
         throw new IllegalStateException("Already installed " + name);

      install(context, trace);
   }

   public synchronized void change(ControllerContext context, ControllerState state) throws Throwable
   {
      boolean trace = log.isTraceEnabled();
     
      if (context == null)
         throw new IllegalArgumentException("Null context");
     
      if (state == null)
         throw new IllegalArgumentException("Null state");
     
      change(context, state, trace);
   }

   public synchronized void enableOnDemand(ControllerContext context) throws Throwable
   {
      boolean trace = log.isTraceEnabled();
     
      if (context == null)
         throw new IllegalArgumentException("Null context");
     
      enableOnDemand(context, trace);
   }

   public synchronized ControllerContext uninstall(Object name)
   {
      boolean trace = log.isTraceEnabled();

      if (name == null)
         throw new IllegalArgumentException("Null name");
     
      if (errorContexts.remove(name) && trace)
         log.trace("Tidied up context in error state: " + name);

      ControllerContext context = (ControllerContext) allContexts.get(name);
      if (context == null)
         throw new IllegalStateException("Not installed: " + name);
     
      if (trace)
         log.trace("Uninstalling " + context.toShortString());
     
      uninstallContext(context, ControllerState.NOT_INSTALLED, trace);

      allContexts.remove(name);
      return context;
   }

   /**
    * Install a context
    *
    * @param context the context
    * @param trace whether trace is enabled
    * @throws Throwable for any error
    */
   protected void install(ControllerContext context, boolean trace) throws Throwable
   {
      Object name = context.getName();
     
      if (ControllerMode.AUTOMATIC.equals(context.getMode()))
         context.setRequiredState(ControllerState.INSTALLED);
     
      if (trace)
         log.trace("Installing " + context.toShortString());

      context.setController(this);
      DependencyInfo dependencies = context.getDependencyInfo();
      if (trace)
         log.trace("Dependencies for " + name + ": " + dependencies.getIDependOn(null));

      if (incrementState(context, trace))
      {
         allContexts.put(context.getName(), context);
         resolveContexts(trace);
      }
      else
      {
         errorContexts.remove(context);
         throw context.getError();
      }
   }

   /**
    * Change a context's state
    *
    * @param context the context
    * @param state the required state
    * @param trace whether trace is enabled
    * @throws Throwable for any error
    */
   protected void change(ControllerContext context, ControllerState state, boolean trace) throws Throwable
   {
      ControllerState fromState = context.getState();
      int currentIndex = states.indexOf(fromState);
      int requiredIndex = states.indexOf(state);
      if (requiredIndex == -1)
         throw new IllegalArgumentException("Unknown state: " + state);
     
      if (currentIndex == requiredIndex)
      {
         if (trace)
            log.trace("No change required toState=" + state.getStateString() + " " + context.toShortString());
         return;
      }
     
      if (trace)
         log.trace("Change toState=" + state.getStateString() + " " + context.toShortString());
     
      context.setRequiredState(state);

      if (currentIndex < requiredIndex)
         resolveContexts(trace);
      else
      {
         while (currentIndex > requiredIndex)
         {
            uninstallContext(context, trace);
            currentIndex = states.indexOf(context.getState());
         }
      }
   }

   /**
    * Enable an on demand context
    *
    * @param context the context
    * @param trace whether trace is enabled
    * @throws Throwable for any error
    */
   protected void enableOnDemand(ControllerContext context, boolean trace) throws Throwable
   {
      if (ControllerMode.ON_DEMAND.equals(context.getMode()) == false)
         throw new IllegalStateException("Context is not ON DEMAND: " + context.toShortString());
     
      if (allContexts.containsKey(context.getName()) == false)
         throw new IllegalStateException("Unknown context: " + context.toShortString());
     
      // Already done
      if (ControllerState.INSTALLED.equals(context.getRequiredState()))
         return;
      context.setRequiredState(ControllerState.INSTALLED);
     
      if (trace)
         log.trace("Enable onDemand: " + context.toShortString());
     
      onDemandEnabled = true;
   }

   /**
    * Increment state
    *
    * @param context the context
    * @param trace whether trace is enabled
    * @return whether the suceeded
    */
   protected boolean incrementState(ControllerContext context, boolean trace)
   {
      ControllerState fromState = context.getState();
     
      Set fromContexts = null;
     
      int currentIndex = -1;
      if (ControllerState.ERROR.equals(fromState))
      {
         errorContexts.remove(context);
         try
         {
            install(context, ControllerState.ERROR, ControllerState.NOT_INSTALLED);
         }
         catch (Throwable t)
         {
            log.error("Error during initial installation: " + context.toShortString(), t);
            context.setError(t);
            errorContexts.add(context);
            return false;
           
         }
         Set notInstalled = (Set) contextsByState.get(ControllerState.NOT_INSTALLED);
         notInstalled.add(context);
      }
      else
      {
         currentIndex = states.indexOf(fromState);
         fromContexts = (Set) contextsByState.get(fromState);
         if (fromContexts.contains(context) == false)
            throw new IllegalStateException("Context not found in previous state: " + context.toShortString());
      }
     
      int toIndex = currentIndex + 1;
      ControllerState toState = (ControllerState) states.get(toIndex);
      Set toContexts = (Set) contextsByState.get(toState);
     
      try
      {
         install(context, fromState, toState);
      }
      catch (Throwable t)
      {
         log.error("Error installing to " + toState.getStateString() + ": " + context.toShortString(), t);
         uninstallContext(context, ControllerState.NOT_INSTALLED, trace);
         context.setError(t);
         errorContexts.add(context);
         return false;
      }
     
      if (fromContexts != null)
         fromContexts.remove(context);
      toContexts.add(context);
      return true;
   }
  
   /**
    * Resolve unresolved contexts
    *
    * @param trace whether trace is enabled
    */
   protected void resolveContexts(boolean trace)
   {
      boolean resolutions = true;
      while (resolutions || onDemandEnabled)
      {
         onDemandEnabled = false;
         resolutions = false;
         for (int i = 0; i < states.size()-1; ++i)
         {
            ControllerState fromState = (ControllerState) states.get(i);
            ControllerState toState = (ControllerState) states.get(i+1);
            if (resolveContexts(fromState, toState, trace))
            {
               resolutions = true;
               break;
            }
         }
      }

      if (trace)
      {
         for (int i = 0; i < states.size()-1; ++i)
         {
            ControllerState state = (ControllerState) states.get(i);
            ControllerState nextState = (ControllerState) states.get(i+1);
            Set stillUnresolved = (Set) contextsByState.get(state);
            if (stillUnresolved.isEmpty() == false)
            {
               for (Iterator j = stillUnresolved.iterator(); j.hasNext();)
               {
                  ControllerContext ctx = (ControllerContext) j.next();
                  if (advance(ctx))
                     log.trace("Still unresolved " + nextState.getStateString() + ": " + ctx);
               }
            }
         }
      }
   }

   /**
    * Resolve contexts
    *
    * @param fromState the from state
    * @param toState the to state
    * @param trace whether trace is enabled
    * @return true when there were resolutions
    */
   protected boolean resolveContexts(ControllerState fromState, ControllerState toState, boolean trace)
   {
      boolean resolutions = false;
      Set unresolved = (Set) contextsByState.get(fromState);
      Set resolved = resolveContexts(unresolved, toState, trace);
      if (resolved.isEmpty() == false)
      {
         for (Iterator i = resolved.iterator(); i.hasNext();)
         {
            ControllerContext context = (ControllerContext) i.next();
            Object name = context.getName();
            if (installing.add(context) == false)
            {
               if (trace)
                  log.trace("Already installing " + name + " for " + toState.getStateString());
            }
            else
            {
               try
               {
                  if (trace)
                     log.trace("Dependencies resolved " + name + " for " + toState.getStateString());

                  if (incrementState(context, trace))
                  {
                     resolutions = true;
                     if (trace)
                        log.trace(name + " " + toState.getStateString());
                  }
               }
               finally
               {
                  installing.remove(context);
               }
            }
         }
      }

      return resolutions;
   }

   /**
    * Resolve contexts
    *
    * @param contexts the contexts
    * @param state the state
    * @param trace whether trace is enabled
    * @return the set of resolved contexts
    */
   protected Set resolveContexts(Set contexts, ControllerState state, boolean trace)
   {
      HashSet result = new HashSet();
     
      if (contexts.isEmpty() == false)
      {
         for (Iterator i = contexts.iterator(); i.hasNext();)
         {
            ControllerContext ctx = (ControllerContext) i.next();
            if (advance(ctx))
            {
               DependencyInfo dependencies = ctx.getDependencyInfo();
               if (dependencies.resolveDependencies(this, state))
                  result.add(ctx);
            }
         }
      }
     
      return result;
   }
  
   /**
    * Uninstall a context
    *
    * @param context the context to uninstall
    * @param toState the target state
    * @param trace whether trace is enabled
    */
   protected void uninstallContext(ControllerContext context, ControllerState toState, boolean trace)
   {
      int targetState = states.indexOf(toState);
      if (targetState == -1)
         log.error("Internal error unknown state " + toState + " states=" + states);

      ControllerState fromState = context.getState();
      int currentState = states.indexOf(fromState);
      if (currentState == -1)
         log.error("Internal error during uninstall current state not found: " + context.toShortString());
     
      if (targetState > currentState)
      {
         log.error("Internal error during uninstall: toState=" + toState + " context=" + context.toShortString());
         return;
      }

      for (int i = currentState; i >= targetState; --i)
         uninstallContext(context, trace);
   }
  
   /**
    * Uninstall a context
    *
    * @param context the context to uninstall
    * @param trace whether trace is enabled
    */
   protected void uninstallContext(ControllerContext context, boolean trace)
   {
      Object name = context.getName();

      ControllerState fromState = context.getState();
      int currentIndex = states.indexOf(fromState);
     
      if (trace)
         log.trace("Uninstalling " + name + " from " + fromState.getStateString());

      Set fromContexts = (Set) contextsByState.get(fromState);
      if (fromContexts.remove(context) == false)
         throw new IllegalStateException("Context not found in previous state " + fromState.getStateString() + " context=" + context.toShortString());
     
      DependencyInfo dependencies = context.getDependencyInfo();
      Set dependsOnMe = dependencies.getDependsOnMe(null);
      if (dependsOnMe.isEmpty() == false)
      {
         for (Iterator i = dependsOnMe.iterator(); i.hasNext();)
         {
            DependencyItem item = (DependencyItem) i.next();
            if (item.isResolved())
            {
               ControllerState dependentState = item.getDependentState();
               if (dependentState == null || dependentState.equals(fromState))
               {
                  item.unresolved(this);
                  ControllerContext dependent = getContext(item.getName(), null);
                  if (dependent != null)
                  {
                     ControllerState whenRequired = item.getWhenRequired();
                     if (whenRequired == null)
                        whenRequired = ControllerState.NOT_INSTALLED;
                     int proposed = states.indexOf(whenRequired);
                     int actual = states.indexOf(dependent.getState());
                     if (proposed <= actual)
                        uninstallContext(dependent, whenRequired, trace);
                  }
               }
            }
         }
      }
     
      int toIndex = currentIndex-1;
      if (toIndex == -1)
      {
         context.setError(new IllegalStateException("Cannot uninstall from " + fromState));
         return;
      }

      ControllerState toState = (ControllerState) states.get(toIndex);
      Set toContexts = (Set) contextsByState.get(toState);
      toContexts.add(context);
     
      try
      {
         uninstall(context, fromState, toState);
      }
      catch (Throwable t)
      {
         log.warn("Error uninstalling from " + fromState.getStateString() + ": " + context.toShortString(), t);
      }
   }
  
   /**
    * Install a context
    *
    * @param context the context
    * @param fromState the from state
    * @param toState the toState
    * @throws Throwable for any error
    */
   protected void install(ControllerContext context, ControllerState fromState, ControllerState toState) throws Throwable
   {
      context.install(fromState, toState);
   }
  
   /**
    * Uninstall a context
    *
    * @param context the context
    * @param fromState the from state
    * @param toState the to state
    */
   protected void uninstall(ControllerContext context, ControllerState fromState, ControllerState toState)
   {
      context.uninstall(fromState, toState);
   }

   /**
    * Whether we should advance the context
    *
    * @param context the context
    * @return true when we should advance the context
    */
   protected boolean advance(ControllerContext context)
   {
      ControllerMode mode = context.getMode();
     
      // Never advance for disabled
      if (ControllerMode.DISABLED.equals(mode))
         return false;
     
      ControllerState fromState = context.getState();
      int fromIndex = states.indexOf(fromState);
      ControllerState requiredState = context.getRequiredState();
      int requiredIndex = states.indexOf(requiredState);
     
      return fromIndex < requiredIndex;
   }
}
TOP

Related Classes of org.jboss.dependency.plugins.AbstractController

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.