Package org.araneaframework.core

Source Code of org.araneaframework.core.BaseComponent$Counter

/**
* Copyright 2006 Webmedia Group Ltd.
*
* 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.
**/

package org.araneaframework.core;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.collections.map.LinkedMap;
import org.apache.log4j.Logger;
import org.araneaframework.Component;
import org.araneaframework.Composite;
import org.araneaframework.Environment;
import org.araneaframework.Message;
import org.araneaframework.Relocatable;

/**
* The base class for all Aranea components. Base entities do not make a Composite pattern
* and only provide some very basic services.
*
* @author "Toomas Römer" <toomas@webmedia.ee>
*/
public abstract class BaseComponent implements Component {
  //*******************************************************************
  // FIELDS
  //*******************************************************************
  private static final Logger log = Logger.getLogger(BaseComponent.class);
 
  private Environment environment;
  private Map children = Collections.synchronizedMap(new LinkedMap());
  private Map disabledChildren = Collections.synchronizedMap(new LinkedMap());
 
  private boolean wasInited = false;
 
  private transient int callCount = 0;
  private transient int reentrantCallCount = 0;
  private transient ThreadLocal reentrantTLS;
 
  private Collection destroyers = new ArrayList();

  //*******************************************************************
  // PUBLIC METHODS
  //*******************************************************************
  public Component.Interface _getComponent() {
    return new ComponentImpl();
  }
     
  //*******************************************************************
  // PROTECTED METHODS
  //*******************************************************************
  /**
   * Init callback. Gets called when the component is initilized.
   */
  protected void init() throws Exception {
  }

  /**
   * Destroy callback. Gets called when the component is destroyed.
   */
  protected void destroy() throws Exception {
  }
 
  protected void disable() throws Exception {   
  }

  protected void enable() throws Exception {   
  } 
 
  protected void propagate(Message message) throws Exception {   
  }
 
  protected void handleException(Exception e) throws Exception {
    throw e;
  }
 
  /**
   * Returns the Environment of this BaseComponent.
   */
  protected Environment getEnvironment() {
    return environment;
  }
 
  /**
   * Returns true, if the BaseComponent has been initialized.
   */
  protected boolean isInitialized() {
    return wasInited;
  }
 
  public void addDestroyer(Standard.Destroyer destroyer) {
    destroyers.add(destroyer);
  }   
 
  /**
   * Sets the environment of this BaseComponent to environment.
   */
  protected void _setEnvironment(Environment env) {
    this.environment = env;
  }

  /**
   * Waits until no call is made to the component. Used to synchronize calls
   * to the component.
   */
  protected synchronized void _waitNoCall() throws InterruptedException {   
    long waitStart = System.currentTimeMillis();
   
    while (callCount != reentrantCallCount) {
      this.wait(1000);
     
      if (callCount != reentrantCallCount) {
        log.warn("Deadlock or starvation suspected, call count=" + callCount + ", reentrant call coint=" + reentrantCallCount);
       
        if (waitStart < System.currentTimeMillis() - 10000) {
          //XXX can't throw this in production...
          throw new AraneaRuntimeException("Deadlock or starvation suspected!");
          //return;
        }
      }
    }   
  }

  /**
   * Checks if a call is valid (component is in the required state), increments the call count.
   */
  protected synchronized void _startCall() throws IllegalStateException {
    _checkCall();
    incCallCount();
  }

  /**
   * Decrements the call count. Wakes up all threads that are waiting on
   * this object's monitor
   */
  protected synchronized void _endCall() {
    decCallCount();
    this.notifyAll();
  }
 
  /**
   * Used for starting a call that is a re-entrant call. Meaning a call of this component
   * is doing the calling
   */
  protected synchronized void _startWaitingCall() {
    if (getReentrantCount() >= 1)
      reentrantCallCount++;
  }
 
  /**
   * Decrements internal callcount counter.
   */
  protected synchronized void _endWaitingCall() {   
    if (getReentrantCount() >= 1)
      reentrantCallCount--;
  }

  /**
   * Checks if this component is initialized. If not, throws IllegalStateException.
   */
  protected void _checkCall() throws IllegalStateException {
    if (!wasInited) {
      throw new IllegalStateException("Component has not been initialized!");
    }
  }
 
  /**
   * Returns the children of this component.
   */
  protected Map _getChildren() {
    return children;
  }
 
  /**
   * Adds a child component to this component with the key and initilizes it with the
   * specified Environment env.
   */
  protected void _addComponent(Object key, Component component, Environment env) throws Exception {
    _checkCall();
   
    // cannot add a child with key that clashes with a disabled child's key
    if (children.containsKey(key)) {
      if (disabledChildren.containsKey(key))
        _enableComponent(key);
      _removeComponent(key);
    }
   
    // Sequence is very important as by the time of init
    // component should be in place since during init the
    // component might be overridden.
    children.put(key, component);
    component._getComponent().init(env);
  }
 
  /**
   * Removes the childcomponent with the specified key from the children and calls destroy on it.
   */
  protected void _removeComponent(Object key) throws Exception {
    _checkCall();
   
    Component comp = (Component)children.get(key);
   
    if (comp == null) {
      return;
    }

    //Sequence is very important, and guarantees that there won't
    //be a second destroy call if the first one doesn't succeed.
    children.remove(key);
    comp._getComponent().destroy();
  }

  /**
   * Disables the child component with the specified key. A disabled child is a child that is removed
   * from the standard set of children
   */
  protected void _disableComponent(Object key) throws Exception {
    _checkCall();
   
    if (!children.containsKey(key)) {
      throw new NoSuchComponentException(key);
    }
   
    ((Component) children.get(key))._getComponent().disable();
    disabledChildren.put(key, children.remove(key));   
  }
 
  /**
   * Enables a disabled child component with the specified key.
   * @param key
   * @throws Exception
   */
  protected void _enableComponent(Object key) throws Exception {
    _checkCall();
   
    if (!disabledChildren.containsKey(key)) {
      throw new NoSuchComponentException(key);
    }
       
    children.put(key, disabledChildren.remove(key));
    ((Component) children.get(key))._getComponent().enable();
  }
 
  /**
   * Relocates parent's child with keyFrom to this BaseComponent with a new key keyTo. The child
   * will get the Environment specified by newEnv. 
   * @param parent is the current parent of the child to be relocated.
   * @param newEnv the new Environment of the child.
   * @param keyFrom is the key of the child to be relocated.
   * @param keyTo is the the key, with which the child will be added to this StandardService.
   */
  protected void _relocateComponent(Composite parent, Environment newEnv, Object keyFrom, Object keyTo) throws Exception {
    if (!(parent._getComposite().getChildren().get(keyFrom) instanceof Relocatable)) {
      throw new AraneaRuntimeException("Child "+keyFrom+" not an instance of Relocatable");
    }
   
    Relocatable comp = (Relocatable) parent._getComposite().detach(keyFrom);
    comp._getRelocatable().overrideEnvironment(newEnv);
   
    children.put(keyTo, comp);
  }
 
  protected void _propagate(Message message) throws Exception {
    Iterator ite = (new HashMap(_getChildren())).keySet().iterator();
    while(ite.hasNext()) {
      Object key = ite.next();
      Component component = (Component)_getChildren().get(key);
     
      if (component == null ) {
        throw new NoSuchComponentException(key);
      }     
     
      message.send(key, component);
    }
  }
 

  //*******************************************************************
  // PRIVATE METHODS
  //*******************************************************************
 
  private void incCallCount() {
    if (reentrantTLS == null)
      reentrantTLS = new ThreadLocal();
   
    if (reentrantTLS.get() == null)
      reentrantTLS.set(new Counter(0));
   
    callCount++;
    ((Counter) reentrantTLS.get()).counter++;
   
    if (getReentrantCount() > 1)
      reentrantCallCount++;
  }
  
  private void decCallCount() {
    if (getReentrantCount() > 1)
      reentrantCallCount--;
   
    callCount--;
    ((Counter) reentrantTLS.get()).counter--;
  }
 
  private int getReentrantCount() {    
    return (reentrantTLS == null || reentrantTLS.get() == null) ? 0 : ((Counter) reentrantTLS.get()).counter;
  }
 
  //*******************************************************************
  // PROTECTED CLASSES
  //*******************************************************************
  //component implementation
  protected class ComponentImpl implements Component.Interface {
   
    public synchronized void init(Environment env) throws Exception {
      if (env == null) {
        throw new AraneaRuntimeException("Environment cannot be null");
      }
     
      if (wasInited) {
        throw new AraneaRuntimeException("Cannot initialize a component more than once");
      }     
      BaseComponent.this._setEnvironment(env);
      wasInited = true;
      BaseComponent.this.init();
    }
   
    public void destroy() throws Exception {    
      _startWaitingCall();
     
      try {
        /* XXX synch logic a bit weird.
         * Second call to destroy should fail, not wait. */
        _waitNoCall();
        synchronized (this) {
          for (Iterator i = new HashMap(_getChildren()).keySet().iterator(); i.hasNext(); ) {
            _removeComponent(i.next());
          }
         
          for (Iterator i = new HashMap(disabledChildren).keySet().iterator(); i.hasNext(); ) {
            Component comp = (Component) disabledChildren.get(i.next());
            if (comp != null) {         
              comp._getComponent().destroy();            
            }
          }   
         
          for (Iterator i = new ArrayList(destroyers).iterator(); i.hasNext(); ) {
            Standard.Destroyer dest = (Standard.Destroyer) i.next();
            dest.destroy();
         
         
          BaseComponent.this.destroy();
        }
        wasInited = false;  
      }
      finally {
        _endWaitingCall();
      }
    }
   
    public void propagate(Message message) throws Exception {
      _startCall();
      try {     
        BaseComponent.this.propagate(message);
      }
      finally {
        _endCall();
      }
    }

    public void enable() throws Exception {
      _startCall();
      try {
        BaseComponent.this.enable();
      }
      finally {
        _endCall();
      }
    }

    public void disable() throws Exception {
      _startCall();
      try {
        BaseComponent.this.disable();
      }
      finally {
        _endCall();
      }
    }
  }
 
  //*******************************************************************
  // PRIVATE CLASSES
  //*******************************************************************
  private static class Counter {
    /**
     * The value of the counter
     */
    public int counter;
   
    /**
     * Initializes the counter with a value.
     * @param counter value of the counter
     */
    public Counter(int counter) {
      this.counter = counter;
    }
  }
}
TOP

Related Classes of org.araneaframework.core.BaseComponent$Counter

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.