Package fr.imag.adele.apam.manager.conflict

Source Code of fr.imag.adele.apam.manager.conflict.ConflictManager

/**
* Copyright 2011-2012 Universite Joseph Fourier, LIG, ADELE team
*   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 fr.imag.adele.apam.manager.conflict;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.felix.ipojo.annotations.Instantiate;
import org.apache.felix.ipojo.annotations.Invalidate;
import org.apache.felix.ipojo.annotations.Provides;
import org.apache.felix.ipojo.annotations.Requires;
import org.apache.felix.ipojo.annotations.Validate;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.imag.adele.apam.Apam;
import fr.imag.adele.apam.ApamManagers;
import fr.imag.adele.apam.CST;
import fr.imag.adele.apam.Component;
import fr.imag.adele.apam.Composite;
import fr.imag.adele.apam.CompositeType;
import fr.imag.adele.apam.ContextualManager;
import fr.imag.adele.apam.DynamicManager;
import fr.imag.adele.apam.Instance;
import fr.imag.adele.apam.Link;
import fr.imag.adele.apam.PropertyManager;
import fr.imag.adele.apam.RelToResolve;
import fr.imag.adele.apam.RelationManager;
import fr.imag.adele.apam.Resolved;
import fr.imag.adele.apam.declarations.ComponentKind;
import fr.imag.adele.apam.declarations.OwnedComponentDeclaration;
import fr.imag.adele.apam.impl.APAMImpl;
import fr.imag.adele.apam.impl.ComponentImpl.InvalidConfiguration;
import fr.imag.adele.apam.impl.CompositeImpl;
import fr.imag.adele.apam.impl.FailedResolutionManager;

/**
* This class is the entry point of the dynamic manager implementation.
*
*
* @author vega
*
*/
@Instantiate(name = "ConflictManager-Instance")
@org.apache.felix.ipojo.annotations.Component(name = "ConflictManager", immediate = true)
@Provides
public class ConflictManager implements ContextualManager, RelationManager, DynamicManager, PropertyManager {

  private final static Logger logger = LoggerFactory.getLogger(ConflictManager.class);

  /**
   * A reference to the APAM machine
   */
  @Requires(proxy = false)
  private Apam apam;

  /**
   * The content managers of all composites in APAM
   */
  private Map<Composite, ContentManager> contentManagers;

  /**
   * The content manager associated with the root composite
   */
  private ContentManager rootManager;

  public ConflictManager(BundleContext context) {
  }

  @Override
  public String getName() {
    return "ConflictManager";
  }

  /**
   * Conflict Manager is a contextual manager, but it does not have its own declared model,
   * all the information is in the component declaration.
   *
   */
  @Override
  public void initializeContext(CompositeType composite) {
  }

  /**
   * For owned instances that could match a resolution request, we must be
   * sure that the grants are respected.
   */
  @Override
  public boolean beginResolving(RelToResolve relation) {

    if (!relation.getTargetKind().equals(ComponentKind.INSTANCE)) {
      return false;
    }

    /**
     * Iterate over all owned instances that could satisfy this request, and verify if access is granted.
     * In case access is not allowed, add the corresponding constraints to the relation
     *
     * WARNING Notice that this is a global validation, irrespective of composites. We verify all visible
     * instances that could satisfy the request.
     */

    for (ContentManager container : getManagers()) {
      container.addGrantConstraints(relation);
    }
   
   
    return false;
  }

  /**
   * This manager only handles conflicts, it doesn't resolve relations. It
   * only participates in resolution to add constraints to enforce conflict
   * management rules.
   */
  @Override
  public Resolved<?> resolve(RelToResolve relation) {
    throw new UnsupportedOperationException("Conflict Manager doesn't resolve relations");
  }

  @Override
  public void addedComponent(Component component) {

    /*
     * Get the list of currently existing managers
     */
    Collection<ContentManager> managers = getManagers();

    /*
     * Create a content manager associated to newly created composites
     */
    if (component instanceof Composite) {

      Composite composite = (Composite) component;

      if (getManager(composite) != null) {
        logger.error("Composite already added in APAM "+ composite.getName());
        return;
      }

      try {

        ContentManager manager = new ContentManager(this, composite);

        /*
         * Validate there is no conflict in ownership declarations with
         * existing composites
         */
        for (ContentManager existingManager : managers) {
          Set<OwnedComponentDeclaration> conflicts = manager.getConflictingDeclarations(existingManager);
          if (!conflicts.isEmpty()) {
            throw new InvalidConfiguration("Invalid owned declaration, conflicts with "+
                      existingManager.getComposite().getName() + ":" + conflicts);
          }
        }

        /*
         * register manager
         */
        synchronized (this) {
          contentManagers.put(composite, manager);
        }

        manager.start();

        /*
         * For all the existing instances we consider the impact of the
         * newly created composite in ownership
         */
        for (Instance instance : CST.componentBroker.getInsts()) {
          verifyOwnership(instance);
        }

      } catch (InvalidConfiguration error) {

        /*
         * TODO We should not add the composite in APAM if the content
         * manager could not be created, but currently there is no way
         * for a manager to signal an error in creation.
         */
        logger.error("Error creating content manager for composite "+ component.getName(), error);
      }
    }

    /*
     * Verify ownership of newly created instances
     */
    if (component instanceof Instance) {
      verifyOwnership((Instance) component);
    }

  }

  @Override
  public void addedLink(Link link) {
  }

  @Override
  public void attributeAdded(Component component, String attr, String newValue) {
    propertyChanged(component, attr);
  }

  @Override
  public void attributeChanged(Component component, String attr, String newValue, String oldValue) {
    propertyChanged(component, attr);
  }

  @Override
  public void attributeRemoved(Component component, String attr, String oldValue) {
    propertyChanged(component, attr);
  }

  /**
   * Give access to the APAM reference
   */
  public Apam getApam() {
    return apam;
  }
 
  /**
   * Give access to the failure manager
   */
  public FailedResolutionManager getFailureManager() {
    return ((APAMImpl)apam).getFailedResolutionManager();
  }

  /**
   * Get the manager associated to a composite
   */
  private synchronized ContentManager getManager(Composite composite) {
    return composite != null ? contentManagers.get(composite) : contentManagers.get(CompositeImpl.getRootAllComposites());
  }

  /**
   * Get a thread safe (stack contained) copy of the current list of managers
   */
  private synchronized Collection<ContentManager> getManagers() {
    return new ArrayList<ContentManager>(contentManagers.values());
  }



  private void propertyChanged(Component component, String property) {

    /*
     * If an instance attribute is modified, this may change ownership
     * and/or the state of its container
     */
    if (component instanceof Instance) {

      verifyOwnership((Instance) component);

      ContentManager container = getManager(((Instance) component).getComposite());
      if (container != null) {
        container.propertyChanged((Instance) component, property);
      }
    }

  }

  @Override
  public void removedComponent(Component component) {

    /*
     * Remove destroyed instance from the content manager of its container
     */
    if (component instanceof Instance) {
      ContentManager container = getManager(((Instance) component).getComposite());
      if (container != null) {
        container.removedInstance((Instance) component);
      }
    }

    /*
     * Remove a content manager when its composite is removed
     */
    if (component instanceof Composite) {
      ContentManager manager = getManager((Composite) component);

      synchronized (this) {
        contentManagers.remove(component);
      }

      manager.dispose();
    }
  }

  @Override
  public void removedLink(Link link) {
  }


  /**
   * This method is automatically invoked when the manager is validated, so we
   * can safely assume that APAM is available
   *
   */
  @Validate
  private synchronized void start() {

    /*
     * Create the default content manager to be associated with the root
     * composite
     */
    try {

      contentManagers = new HashMap<Composite, ContentManager>();

      Composite root = CompositeImpl.getRootAllComposites();
      rootManager = new ContentManager(this, root);

      contentManagers.put(root, rootManager);
      rootManager.start();

    } catch (InvalidConfiguration ignored) {
    }

    /*
     * Register with APAM
     */
    ApamManagers.addRelationManager(this, Priority.HIGHEST);
    ApamManagers.addDynamicManager(this);
    ApamManagers.addPropertyManager(this);

    /*
     * TODO if conflict manager is started or restarted after APAM, should
     * we verify if there are already created composites?
     */
  }

  /**
   * This method is automatically invoked when the manager is invalidated, so
   * APAM is no longer available
   */
  @Invalidate
  private synchronized void stop() {
    ApamManagers.removeRelationManager(this);
    ApamManagers.removeDynamicManager(this);
    ApamManagers.removePropertyManager(this);
  }

  /**
   * Set the ownership of an instance to one of the requesting composites,
   * signal any detected conflict
   */
  private void verifyOwnership(Instance instance) {

    /*
     * Verify that the current container is registered in dynaman, otherwise
     * postpone handling of the event
     */
    ContentManager container = getManager(instance.getComposite());
    if (container == null) {
      return;
    }

    Collection<ContentManager> managers = getManagers();
    ContentManager owner = container.owns(instance) ? container : null;

    /*
     * Get the list of composites requesting ownership.
     */
    List<ContentManager> requesters = new ArrayList<ContentManager>();
    StringBuffer requestersNames = new StringBuffer();

    for (ContentManager manager : managers) {
      if (manager.shouldOwn(instance)) {
        requesters.add(manager);

        requestersNames.append(" ");
        requestersNames.append(manager.getComposite().getName());
      }
    }

    /*
     * If there is conflicting requests signal an error
     *
     * TODO In some cases we could do more than simply logging the error.
     * Perhaps avoiding creating composites that will produce conflicts.
     */
    if (requesters.size() > 1) {
      logger.error("Conflict in ownership : composites ("+ requestersNames + ") request ownership of instance "+ instance.getName());
    }

    /*
     * If there is no ownership request continue processing event
     */
    if (requesters.isEmpty()) {
      return;
    }

    /*
     * Choose an owner arbitrarily among requesters (try to keep the current
     * owner if exists)
     */
    ContentManager newOwner = requesters.isEmpty() ? null : requesters.contains(container) ? container : requesters.get(0);

    /*
     * Revoke ownership to previous owner (if it has changed)
     */
    if (owner != null && (newOwner == null || !newOwner.equals(owner))) {
      owner.revokeOwnership(instance);
    }

    /*
     * Accord ownership to new owner (if it has changed)
     */
    if (newOwner != null && (owner == null || !owner.equals(newOwner))) {
      newOwner.accordOwnership(instance);
    }
  }

}
TOP

Related Classes of fr.imag.adele.apam.manager.conflict.ConflictManager

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.