Package org.eclipse.core.internal.registry

Source Code of org.eclipse.core.internal.registry.RegistryObjectManager

/*******************************************************************************
* Copyright (c) 2004, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.core.internal.registry;

import java.lang.ref.SoftReference;
import java.util.*;
import org.eclipse.core.runtime.InvalidRegistryObjectException;
import org.eclipse.core.runtime.spi.RegistryContributor;

/**
* This class manage all the object from the registry but does not deal with their dependencies.
* It serves the objects which are either directly obtained from memory or read from a cache.
* It also returns handles for objects.
*/
public class RegistryObjectManager implements IObjectManager {
  //Constants used to get the objects and their handles
  static public final byte CONFIGURATION_ELEMENT = 1;
  static public final byte EXTENSION = 2;
  static public final byte EXTENSION_POINT = 3;
  static public final byte THIRDLEVEL_CONFIGURATION_ELEMENT = 4;

  static final int CACHE_INITIAL_SIZE = 512; //This value has been picked because it is the minimal size required to startup an RCP app. (FYI, eclipse requires 3 growths).
  static final float DEFAULT_LOADFACTOR = 0.75f; //This is the default factor used in reference map.

  static final int[] EMPTY_INT_ARRAY = new int[0];
  static final String[] EMPTY_STRING_ARRAY = new String[0];

  static int UNKNOWN = -1;

  // key: extensionPointName, value: object id
  private HashtableOfStringAndInt extensionPoints; //This is loaded on startup. Then entries can be added when loading a new plugin from the xml.
  // key: object id, value: an object
  private ReferenceMap cache; //Entries are added by getter. The structure is not thread safe.
  //key: int, value: int
  private HashtableOfInt fileOffsets; //This is read once on startup when loading from the cache. Entries are never added here. They are only removed to prevent "removed" objects to be reloaded.

  private int nextId = 1; //This is only used to get the next number available.

  //Those two data structures are only used when the addition or the removal of a plugin occurs.
  //They are used to keep track on a contributor basis of the extension being added or removed
  private KeyedHashSet newContributions; //represents the contributers added during this session.
  private Object formerContributions; //represents the contributers encountered in previous sessions. This is loaded lazily.

  private HashMap contributors; // key: contributor ID; value: contributor name
  private HashMap removedContributors; // key: contributor ID; value: contributor name
  private KeyedHashSet namespacesIndex; // registry elements (extension & extensionpoints) indexed by namespaces

  // Map key: extensionPointFullyQualifiedName, value int[] of orphan extensions.
  // The orphan access does not need to be synchronized because the it is protected by the lock in extension registry.
  private Object orphanExtensions;

  private KeyedHashSet heldObjects = new KeyedHashSet(); //strong reference to the objects that must be hold on to

  //Indicate if objects have been removed or added from the table. This only needs to be set in a couple of places (addNamespace and removeNamespace)
  private boolean isDirty = false;

  private boolean fromCache = false;

  private ExtensionRegistry registry;

  // TODO this option is not used
  // OSGI system properties.  Copied from EclipseStarter
  public static final String PROP_NO_REGISTRY_FLUSHING = "eclipse.noRegistryFlushing"; //$NON-NLS-1$

  public RegistryObjectManager(ExtensionRegistry registry) {
    extensionPoints = new HashtableOfStringAndInt();
    if ("true".equalsIgnoreCase(RegistryProperties.getProperty(PROP_NO_REGISTRY_FLUSHING))) { //$NON-NLS-1$
      cache = new ReferenceMap(ReferenceMap.HARD, CACHE_INITIAL_SIZE, DEFAULT_LOADFACTOR);
    } else {
      cache = new ReferenceMap(ReferenceMap.SOFT, CACHE_INITIAL_SIZE, DEFAULT_LOADFACTOR);
    }
    newContributions = new KeyedHashSet();
    fileOffsets = new HashtableOfInt();

    this.registry = registry;
  }

  /**
   * Initialize the object manager. Return true if the initialization succeeded, false otherwise
   */
  synchronized boolean init(long timeStamp) {
    TableReader reader = registry.getTableReader();
    Object[] results = reader.loadTables(timeStamp);
    if (results == null) {
      return false;
    }
    fileOffsets = (HashtableOfInt) results[0];
    extensionPoints = (HashtableOfStringAndInt) results[1];
    nextId = ((Integer) results[2]).intValue();
    fromCache = true;

    if (!registry.useLazyCacheLoading()) {
      //TODO Here we could grow all the tables to the right size (ReferenceMap)
      reader.setHoldObjects(true);
      markOrphansHasDirty(getOrphans());
      fromCache = reader.readAllCache(this);
      formerContributions = getFormerContributions();
    }
    return fromCache;
  }

  synchronized void addContribution(Contribution contribution) {
    isDirty = true;
    Object Id = contribution.getKey();

    KeyedElement existingContribution = getFormerContributions().getByKey(Id);
    if (existingContribution != null) { // move it from former to new contributions
      removeContribution(Id);
      newContributions.add(existingContribution);
    } else
      existingContribution = newContributions.getByKey(Id);

    if (existingContribution != null) // merge
      ((Contribution) existingContribution).mergeContribution(contribution);
    else
      newContributions.add(contribution);

    updateNamespaceIndex(contribution, true);
  }

  // TODO make ExtensionPoint, Extension provide namespace in a same way (move it to the RegistryObject?)
  // See if all the registryObjects have the same namespace. If not, return null.
  // Also can return null if empty array is passed in or objects are of an unexpected type
  private String findCommonNamespaceIdentifier(RegistryObject[] registryObjects) {
    String namespaceName = null;
    for (int i = 0; i < registryObjects.length; i++) {
      RegistryObject currentObject = registryObjects[i];
      String tmp = null;
      if (currentObject instanceof ExtensionPoint)
        tmp = ((ExtensionPoint) currentObject).getNamespace();
      else if (currentObject instanceof Extension)
        tmp = ((Extension) currentObject).getNamespaceIdentifier();

      if (namespaceName == null) {
        namespaceName = tmp;
        continue;
      }
      if (!namespaceName.equals(tmp)) {
        return null;
      }
    }
    return namespaceName;
  }

  synchronized void removeExtensionPointFromNamespaceIndex(int extensionPoint, String namespaceName) {
    RegistryIndexElement indexElement = getNamespaceIndex(namespaceName);
    indexElement.updateExtensionPoint(extensionPoint, false);
  }

  synchronized void removeExtensionFromNamespaceIndex(int extensions, String namespaceName) {
    RegistryIndexElement indexElement = getNamespaceIndex(namespaceName);
    indexElement.updateExtension(extensions, false);
  }

  // Called from a synchronized method
  private void updateNamespaceIndex(Contribution contribution, boolean added) {
    // if all extension points are from the same namespace combine them in one block and add them all together
    int[] contribExtensionPoints = contribution.getExtensionPoints();
    RegistryObject[] extensionPointObjects = getObjects(contribExtensionPoints, EXTENSION_POINT);
    String commonExptsNamespace = null;
    if (contribExtensionPoints.length > 1)
      commonExptsNamespace = findCommonNamespaceIdentifier(extensionPointObjects);
    if (commonExptsNamespace != null) {
      RegistryIndexElement indexElement = getNamespaceIndex(commonExptsNamespace);
      indexElement.updateExtensionPoints(contribExtensionPoints, added);
    } else {
      for (int i = 0; i < contribExtensionPoints.length; i++) {
        String namespaceName = ((ExtensionPoint) extensionPointObjects[i]).getNamespace();
        RegistryIndexElement indexElement = getNamespaceIndex(namespaceName);
        indexElement.updateExtensionPoint(contribExtensionPoints[i], added);
      }
    }

    // if all extensions are from the same namespace combine them in one block and add them all together
    int[] contrExtensions = contribution.getExtensions();
    RegistryObject[] extensionObjects = getObjects(contrExtensions, EXTENSION);
    String commonExtNamespace = null;
    if (contrExtensions.length > 1)
      commonExtNamespace = findCommonNamespaceIdentifier(extensionObjects);
    if (commonExtNamespace != null) {
      RegistryIndexElement indexElement = getNamespaceIndex(commonExtNamespace);
      indexElement.updateExtensions(contrExtensions, added);
    } else {
      for (int i = 0; i < contrExtensions.length; i++) {
        String namespaceName = ((Extension) extensionObjects[i]).getNamespaceIdentifier();
        RegistryIndexElement indexElement = getNamespaceIndex(namespaceName);
        indexElement.updateExtension(contrExtensions[i], added);
      }
    }
  }

  synchronized int[] getExtensionPointsFrom(String id) {
    KeyedElement tmp = newContributions.getByKey(id);
    if (tmp == null)
      tmp = getFormerContributions().getByKey(id);
    if (tmp == null)
      return EMPTY_INT_ARRAY;
    return ((Contribution) tmp).getExtensionPoints();
  }

  synchronized boolean hasContribution(String id) {
    Object result = newContributions.getByKey(id);
    if (result == null)
      result = getFormerContributions().getByKey(id);
    return result != null;
  }

  private KeyedHashSet getFormerContributions() {
    KeyedHashSet result;
    if (fromCache == false)
      return new KeyedHashSet(0);

    if (formerContributions == null || (result = ((KeyedHashSet) ((formerContributions instanceof SoftReference) ? ((SoftReference) formerContributions).get() : formerContributions))) == null) {
      result = registry.getTableReader().loadContributions();
      formerContributions = new SoftReference(result);
    }
    return result;
  }

  synchronized public void add(RegistryObject registryObject, boolean hold) {
    if (registryObject.getObjectId() == UNKNOWN) {
      int id = nextId++;
      registryObject.setObjectId(id);
    }
    cache.put(registryObject.getObjectId(), registryObject);
    if (hold)
      hold(registryObject);
  }

  private void remove(RegistryObject registryObject, boolean release) {
    cache.remove(registryObject.getObjectId());
    if (release)
      release(registryObject);
  }

  synchronized void remove(int id, boolean release) {
    RegistryObject toRemove = (RegistryObject) cache.get(id);
    if (fileOffsets != null)
      fileOffsets.removeKey(id);
    if (toRemove != null)
      remove(toRemove, release);
  }

  private void hold(RegistryObject toHold) {
    heldObjects.add(toHold);
  }

  private void release(RegistryObject toRelease) {
    heldObjects.remove(toRelease);
  }

  public synchronized Object getObject(int id, byte type) {
    return basicGetObject(id, type);
  }

  private Object basicGetObject(int id, byte type) {
    Object result = cache.get(id);
    if (result != null)
      return result;
    if (fromCache)
      result = load(id, type);
    if (result == null)
      throw new InvalidRegistryObjectException();
    cache.put(id, result);
    return result;
  }

  // The current impementation of this method assumes that we don't cache dynamic
  // extension. In this case all extensions not yet loaded (i.e. not in the memory cache)
  // are "not dynamic" and we actually check memory objects to see if they are dynamic.
  //
  // If we decide to allow caching of dynamic objects, the implementation
  // of this method would have to retrieved the object from disk and check
  // its "dynamic" status. The problem is that id alone is not enough to get the object
  // from the disk; object type is needed as well.
  public boolean shouldPersist(int id) {
    Object result = cache.get(id);
    if (result != null)
      return ((RegistryObject) result).shouldPersist();
    return true;
  }

  public synchronized RegistryObject[] getObjects(int[] values, byte type) {
    if (values.length == 0) {
      switch (type) {
        case EXTENSION_POINT :
          return ExtensionPoint.EMPTY_ARRAY;
        case EXTENSION :
          return Extension.EMPTY_ARRAY;
        case CONFIGURATION_ELEMENT :
        case THIRDLEVEL_CONFIGURATION_ELEMENT :
          return ConfigurationElement.EMPTY_ARRAY;
      }
    }

    RegistryObject[] results = null;
    switch (type) {
      case EXTENSION_POINT :
        results = new ExtensionPoint[values.length];
        break;
      case EXTENSION :
        results = new Extension[values.length];
        break;
      case CONFIGURATION_ELEMENT :
      case THIRDLEVEL_CONFIGURATION_ELEMENT :
        results = new ConfigurationElement[values.length];
        break;
    }
    for (int i = 0; i < values.length; i++) {
      results[i] = (RegistryObject) basicGetObject(values[i], type);
    }
    return results;
  }

  synchronized ExtensionPoint getExtensionPointObject(String xptUniqueId) {
    int id;
    if ((id = extensionPoints.get(xptUniqueId)) == HashtableOfStringAndInt.MISSING_ELEMENT)
      return null;
    return (ExtensionPoint) getObject(id, EXTENSION_POINT);
  }

  public Handle getHandle(int id, byte type) {
    switch (type) {
      case EXTENSION_POINT :
        return new ExtensionPointHandle(this, id);

      case EXTENSION :
        return new ExtensionHandle(this, id);

      case CONFIGURATION_ELEMENT :
        return new ConfigurationElementHandle(this, id);

      case THIRDLEVEL_CONFIGURATION_ELEMENT :
      default : //avoid compiler error, type should always be known
        return new ThirdLevelConfigurationElementHandle(this, id);
    }
  }

  public Handle[] getHandles(int[] ids, byte type) {
    Handle[] results = null;
    int nbrId = ids.length;
    switch (type) {
      case EXTENSION_POINT :
        if (nbrId == 0)
          return ExtensionPointHandle.EMPTY_ARRAY;
        results = new ExtensionPointHandle[nbrId];
        for (int i = 0; i < nbrId; i++) {
          results[i] = new ExtensionPointHandle(this, ids[i]);
        }
        break;

      case EXTENSION :
        if (nbrId == 0)
          return ExtensionHandle.EMPTY_ARRAY;
        results = new ExtensionHandle[nbrId];
        for (int i = 0; i < nbrId; i++) {
          results[i] = new ExtensionHandle(this, ids[i]);
        }
        break;

      case CONFIGURATION_ELEMENT :
        if (nbrId == 0)
          return ConfigurationElementHandle.EMPTY_ARRAY;
        results = new ConfigurationElementHandle[nbrId];
        for (int i = 0; i < nbrId; i++) {
          results[i] = new ConfigurationElementHandle(this, ids[i]);
        }
        break;

      case THIRDLEVEL_CONFIGURATION_ELEMENT :
        if (nbrId == 0)
          return ConfigurationElementHandle.EMPTY_ARRAY;
        results = new ThirdLevelConfigurationElementHandle[nbrId];
        for (int i = 0; i < nbrId; i++) {
          results[i] = new ThirdLevelConfigurationElementHandle(this, ids[i]);
        }
        break;
    }
    return results;
  }

  synchronized ExtensionPointHandle[] getExtensionPointsHandles() {
    return (ExtensionPointHandle[]) getHandles(extensionPoints.getValues(), EXTENSION_POINT);
  }

  synchronized ExtensionPointHandle getExtensionPointHandle(String xptUniqueId) {
    int id = extensionPoints.get(xptUniqueId);
    if (id == HashtableOfStringAndInt.MISSING_ELEMENT)
      return null;
    return (ExtensionPointHandle) getHandle(id, EXTENSION_POINT);
  }

  private Object load(int id, byte type) {
    TableReader reader = registry.getTableReader();
    int offset = fileOffsets.get(id);
    if (offset == Integer.MIN_VALUE)
      return null;
    switch (type) {
      case CONFIGURATION_ELEMENT :
        return reader.loadConfigurationElement(offset);

      case THIRDLEVEL_CONFIGURATION_ELEMENT :
        return reader.loadThirdLevelConfigurationElements(offset, this);

      case EXTENSION :
        return reader.loadExtension(offset);

      case EXTENSION_POINT :
      default : //avoid compile errors. type must always be known
        return reader.loadExtensionPointTree(offset, this);
    }
  }

  synchronized int[] getExtensionsFrom(String contributorId) {
    KeyedElement tmp = newContributions.getByKey(contributorId);
    if (tmp == null)
      tmp = getFormerContributions().getByKey(contributorId);
    if (tmp == null)
      return EMPTY_INT_ARRAY;
    return ((Contribution) tmp).getExtensions();
  }

  synchronized boolean addExtensionPoint(ExtensionPoint currentExtPoint, boolean hold) {
    String uniqueId = currentExtPoint.getUniqueIdentifier();
    if (extensionPoints.get(uniqueId) != HashtableOfStringAndInt.MISSING_ELEMENT)
      return false;
    add(currentExtPoint, hold);
    extensionPoints.put(uniqueId, currentExtPoint.getObjectId());
    return true;
  }

  synchronized void removeExtensionPoint(String extensionPointId) {
    int pointId = extensionPoints.removeKey(extensionPointId);
    if (pointId == HashtableOfStringAndInt.MISSING_ELEMENT)
      return;
    remove(pointId, true);
  }

  public boolean isDirty() {
    return isDirty;
  }

  synchronized void removeContribution(Object contributorId) {
    boolean removed = newContributions.removeByKey(contributorId);
    if (removed == false) {
      removed = getFormerContributions().removeByKey(contributorId);
      if (removed)
        formerContributions = getFormerContributions(); //This forces the removed namespace to stay around, so we do not forget about removed namespaces
    }

    if (removed) {
      isDirty = true;
      return;
    }

  }

  private Map getOrphans() {
    Object result = orphanExtensions;
    if (orphanExtensions == null && !fromCache) {
      result = new HashMap();
      orphanExtensions = result;
    } else if (orphanExtensions == null || (result = ((HashMap) ((orphanExtensions instanceof SoftReference) ? ((SoftReference) orphanExtensions).get() : orphanExtensions))) == null) {
      result = registry.getTableReader().loadOrphans();
      orphanExtensions = new SoftReference(result);
    }
    return (HashMap) result;
  }

  void addOrphans(String extensionPoint, int[] extensions) {
    Map orphans = getOrphans();
    int[] existingOrphanExtensions = (int[]) orphans.get(extensionPoint);

    if (existingOrphanExtensions != null) {
      // just add
      int[] newOrphanExtensions = new int[existingOrphanExtensions.length + extensions.length];
      System.arraycopy(existingOrphanExtensions, 0, newOrphanExtensions, 0, existingOrphanExtensions.length);
      System.arraycopy(extensions, 0, newOrphanExtensions, existingOrphanExtensions.length, extensions.length);
      orphans.put(extensionPoint, newOrphanExtensions);
    } else {
      // otherwise this is the first one
      orphans.put(extensionPoint, extensions);
    }
    markOrphansHasDirty(orphans);
  }

  void markOrphansHasDirty(Map orphans) {
    orphanExtensions = orphans;
  }

  void addOrphan(String extensionPoint, int extension) {
    Map orphans = getOrphans();
    int[] existingOrphanExtensions = (int[]) orphans.get(extensionPoint);

    if (existingOrphanExtensions != null) {
      // just add
      int[] newOrphanExtensions = new int[existingOrphanExtensions.length + 1];
      System.arraycopy(existingOrphanExtensions, 0, newOrphanExtensions, 0, existingOrphanExtensions.length);
      newOrphanExtensions[existingOrphanExtensions.length] = extension;
      orphans.put(extensionPoint, newOrphanExtensions);
    } else {
      // otherwise this is the first one
      orphans.put(extensionPoint, new int[] {extension});
    }
    markOrphansHasDirty(orphans);
  }

  int[] removeOrphans(String extensionPoint) {
    Map orphans = getOrphans();
    int[] existingOrphanExtensions = (int[]) orphans.remove(extensionPoint);
    if (existingOrphanExtensions != null) {
      markOrphansHasDirty(orphans);
    }
    return existingOrphanExtensions;
  }

  void removeOrphan(String extensionPoint, int extension) {
    Map orphans = getOrphans();
    int[] existingOrphanExtensions = (int[]) orphans.get(extensionPoint);

    if (existingOrphanExtensions == null)
      return;

    markOrphansHasDirty(orphans);
    int newSize = existingOrphanExtensions.length - 1;
    if (newSize == 0) {
      orphans.remove(extensionPoint);
      return;
    }

    int[] newOrphanExtensions = new int[existingOrphanExtensions.length - 1];
    for (int i = 0, j = 0; i < existingOrphanExtensions.length; i++)
      if (extension != existingOrphanExtensions[i])
        newOrphanExtensions[j++] = existingOrphanExtensions[i];

    orphans.put(extensionPoint, newOrphanExtensions);
    return;
  }

  //This method is only used by the writer to reach in
  Map getOrphanExtensions() {
    return getOrphans();
  }

  //  This method is only used by the writer to reach in
  int getNextId() {
    return nextId;
  }

  //  This method is only used by the writer to reach in
  HashtableOfStringAndInt getExtensionPoints() {
    return extensionPoints;
  }

  //  This method is only used by the writer to reach in
  KeyedHashSet[] getContributions() {
    return new KeyedHashSet[] {newContributions, getFormerContributions()};
  }

  // This method is used internally and by the writer to reach in. Notice that it doesn't
  // return contributors marked as removed.
  HashMap getContributors() {
    if (contributors == null) {
      if (fromCache == false)
        contributors = new HashMap();
      else
        contributors = registry.getTableReader().loadContributors();
    }
    return contributors;
  }

  synchronized RegistryContributor getContributor(String id) {
    RegistryContributor contributor = (RegistryContributor) getContributors().get(id);
    if (contributor != null)
      return contributor;
    // check if we have it among removed contributors - potentially
    // notification of removals might be processed after the contributor
    // marked as removed:
    if (removedContributors != null)
      return (RegistryContributor) removedContributors.get(id);
    return null;
  }

  // only adds a contributor if it is not already present in the table
  synchronized void addContributor(RegistryContributor newContributor) {
    String key = newContributor.getActualId();
    if (!getContributors().containsKey(key)) {
      isDirty = true;
      if (removedContributors != null)
        removedContributors.remove(key);
      getContributors().put(key, newContributor);
    }
  }

  synchronized void removeContributor(String id) {
    isDirty = true;
    RegistryContributor removed = (RegistryContributor) getContributors().remove(id);
    if (removed != null) {
      if (removedContributors == null)
        removedContributors = new HashMap();
      removedContributors.put(id, removed);
    }
  }

  KeyedHashSet getNamespacesIndex() {
    if (namespacesIndex == null) {
      if (fromCache == false)
        namespacesIndex = new KeyedHashSet(0);
      else
        namespacesIndex = registry.getTableReader().loadNamespaces();
    }
    return namespacesIndex;
  }

  // Find or create required index element
  private RegistryIndexElement getNamespaceIndex(String namespaceName) {
    RegistryIndexElement indexElement = (RegistryIndexElement) getNamespacesIndex().getByKey(namespaceName);
    if (indexElement == null) {
      indexElement = new RegistryIndexElement(namespaceName);
      namespacesIndex.add(indexElement);
    }
    return indexElement;
  }

  /**
   * Collect all the objects that are removed by this operation and store
   * them in a IObjectManager so that they can be accessed from the appropriate
   * deltas but not from the registry.
   */
  synchronized Map getAssociatedObjects(String contributionId) {
    //Collect all the objects associated with this contribution
    int[] xpts = getExtensionPointsFrom(contributionId);
    int[] exts = getExtensionsFrom(contributionId);
    Map actualObjects = new HashMap(xpts.length + exts.length);
    for (int i = 0; i < exts.length; i++) {
      Extension tmp = (Extension) basicGetObject(exts[i], RegistryObjectManager.EXTENSION);
      actualObjects.put(new Integer(exts[i]), tmp);
      collectChildren(tmp, 0, actualObjects);
    }
    for (int i = 0; i < xpts.length; i++) {
      ExtensionPoint xpt = (ExtensionPoint) basicGetObject(xpts[i], RegistryObjectManager.EXTENSION_POINT);
      actualObjects.put(new Integer(xpts[i]), xpt);
    }

    return actualObjects;
  }

  /**
   * Add to the set of the objects all extensions and extension points that
   * could be navigated to from the objects in the set.
   */
  synchronized void addNavigableObjects(Map associatedObjects) {
    Map result = new HashMap();
    for (Iterator iter = associatedObjects.values().iterator(); iter.hasNext();) {
      RegistryObject object = (RegistryObject) iter.next();
      if (object instanceof Extension) {
        // add extension point
        ExtensionPoint extPoint = getExtensionPointObject(((Extension) object).getExtensionPointIdentifier());
        if (extPoint == null) // already removed?
          continue;

        Integer extPointIndex = new Integer(extPoint.getKeyHashCode());
        if (!associatedObjects.containsKey(extPointIndex))
          result.put(new Integer(extPoint.getKeyHashCode()), extPoint);

        // add all extensions for the extension point
        int[] extensions = extPoint.getRawChildren();
        for (int j = 0; j < extensions.length; j++) {
          Extension tmp = (Extension) basicGetObject(extensions[j], RegistryObjectManager.EXTENSION);
          if (tmp == null) // already removed
            continue;
          Integer extensionIndex = new Integer(extensions[j]);
          if (!associatedObjects.containsKey(extensionIndex)) {
            result.put(extensionIndex, tmp);
            collectChildren(tmp, 0, result);
          }
        }
      }
      else if (object instanceof ExtensionPoint) {
        // by now extensions of this extension point have been marked as orphans
        Map orphans = getOrphans();
        String name = ((ExtensionPoint)object).getUniqueIdentifier();
        int[] extensions = (int[]) orphans.get(name);
        if (extensions != null) {
          for (int j = 0; j < extensions.length; j++) {
            Extension tmp = (Extension) basicGetObject(extensions[j], RegistryObjectManager.EXTENSION);
            if (tmp == null) // already removed
              continue;
            Integer extensionIndex = new Integer(extensions[j]);
            if (!associatedObjects.containsKey(extensionIndex)) {
              result.put(extensionIndex, tmp);
              collectChildren(tmp, 0, result);
            }
          }
        }
      }
    }
    associatedObjects.putAll(result);
  }

  synchronized void removeObjects(Map associatedObjects) {
    //Remove the objects from the main object manager so they can no longer be accessed.
    Collection allValues = associatedObjects.values();
    for (Iterator iter = allValues.iterator(); iter.hasNext();) {
      RegistryObject toRemove = (RegistryObject) iter.next();
      remove((toRemove).getObjectId(), true);
      if (toRemove instanceof ExtensionPoint)
        removeExtensionPoint(((ExtensionPoint) toRemove).getUniqueIdentifier());
    }
  }

  IObjectManager createDelegatingObjectManager(Map object) {
    return new TemporaryObjectManager(object, this);
  }

  private void collectChildren(RegistryObject ce, int level, Map collector) {
    ConfigurationElement[] children = (ConfigurationElement[]) getObjects(ce.getRawChildren(), level == 0 || ce.noExtraData() ? RegistryObjectManager.CONFIGURATION_ELEMENT : RegistryObjectManager.THIRDLEVEL_CONFIGURATION_ELEMENT);
    for (int j = 0; j < children.length; j++) {
      collector.put(new Integer(children[j].getObjectId()), children[j]);
      collectChildren(children[j], level + 1, collector);
    }
  }

  public void close() {
    //do nothing.
  }

  public ExtensionRegistry getRegistry() {
    return registry;
  }

  // Called from a synchronized method only
  private boolean unlinkChildFromContributions(KeyedElement[] contributions, int id) {
    for (int i = 0; i < contributions.length; i++) {
      Contribution candidate = (Contribution) contributions[i];
      if (candidate == null)
        continue;
      if (candidate.hasChild(id)) {
        candidate.unlinkChild(id);
        if (candidate.isEmpty())
          removeContribution(candidate.getContributorId());
        return true;
      }
    }
    return false;
  }

  synchronized boolean unlinkChildFromContributions(int id) {
    if (unlinkChildFromContributions(newContributions.elements, id))
      return true;
    return unlinkChildFromContributions(getFormerContributions().elements, id);
  }

  synchronized public ExtensionPointHandle[] getExtensionPointsFromNamespace(String namespaceName) {
    RegistryIndexElement indexElement = getNamespaceIndex(namespaceName);
    int[] namespaceExtensionPoints = indexElement.getExtensionPoints();
    return (ExtensionPointHandle[]) getHandles(namespaceExtensionPoints, EXTENSION_POINT);
  }

  static final ExtensionHandle[] EMPTY_EXTENSIONS_ARRAY = new ExtensionHandle[0];

  // This method filters out extensions with no extension point
  synchronized public ExtensionHandle[] getExtensionsFromNamespace(String namespaceName) {
    RegistryIndexElement indexElement = getNamespaceIndex(namespaceName);
    int[] namespaceExtensions = indexElement.getExtensions();

    // filter extensions with no extension point (orphan extensions)
    List tmp = new ArrayList();
    Extension[] exts = (Extension[]) getObjects(namespaceExtensions, EXTENSION);
    for (int i = 0; i < exts.length; i++) {
      if (getExtensionPointObject(exts[i].getExtensionPointIdentifier()) != null)
        tmp.add(getHandle(exts[i].getObjectId(), EXTENSION));
    }
    if (tmp.size() == 0)
      return EMPTY_EXTENSIONS_ARRAY;
    ExtensionHandle[] result = new ExtensionHandle[tmp.size()];
    return (ExtensionHandle[]) tmp.toArray(result);
  }
}
TOP

Related Classes of org.eclipse.core.internal.registry.RegistryObjectManager

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.