Package org.eclipse.ui.internal.services

Source Code of org.eclipse.ui.internal.services.RegistryPersistence

/*******************************************************************************
* Copyright (c) 2005, 2007 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.ui.internal.services;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.IParameter;
import org.eclipse.core.commands.Parameterization;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.expressions.ElementHandler;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionConverter;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IRegistryChangeEvent;
import org.eclipse.core.runtime.IRegistryChangeListener;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
import org.eclipse.ui.internal.util.Util;
import org.eclipse.ui.services.IDisposable;

/**
* <p>
* A manager for items parsed from the registry. This attaches a listener to the
* registry after the first read, and monitors the registry for changes from
* that point on. When {@link #dispose()} is called, the listener is detached.
* </p>
* <p>
* This class is only intended for internal use within the
* <code>org.eclipse.ui.workbench</code> plug-in.
* </p>
*
* @since 3.2
*/
public abstract class RegistryPersistence implements IDisposable,
    IWorkbenchRegistryConstants {

  /**
   * The expression to return when there is an error. Never <code>null</code>.
   */
  protected static final Expression ERROR_EXPRESSION = new Expression() {
    public final EvaluationResult evaluate(final IEvaluationContext context) {
      return null;
    }
  };

  /**
   * Inserts the given element into the indexed two-dimensional array in the
   * array at the index. The array is grown as necessary.
   *
   * @param elementToAdd
   *            The element to add to the indexed array; may be
   *            <code>null</code>
   * @param indexedArray
   *            The two-dimensional array that is indexed by element type;
   *            must not be <code>null</code>.
   * @param index
   *            The index at which the element should be added; must be a
   *            valid index.
   * @param currentCount
   *            The current number of items in the array at the index.
   */
  protected static final void addElementToIndexedArray(
      final IConfigurationElement elementToAdd,
      final IConfigurationElement[][] indexedArray, final int index,
      final int currentCount) {
    final IConfigurationElement[] elements;
    if (currentCount == 0) {
      elements = new IConfigurationElement[1];
      indexedArray[index] = elements;
    } else {
      if (currentCount >= indexedArray[index].length) {
        final IConfigurationElement[] copy = new IConfigurationElement[indexedArray[index].length * 2];
        System.arraycopy(indexedArray[index], 0, copy, 0, currentCount);
        elements = copy;
        indexedArray[index] = elements;
      } else {
        elements = indexedArray[index];
      }
    }
    elements[currentCount] = elementToAdd;
  }

  /**
   * Adds a warning to be logged at some later point in time.
   *
   * @param warningsToLog
   *            The collection of warnings to be logged; must not be
   *            <code>null</code>.
   * @param message
   *            The mesaage to log; must not be <code>null</code>.
   * @param element
   *            The element from which the warning originates; may be
   *            <code>null</code>.
   */
  protected static final void addWarning(final List warningsToLog,
      final String message, final IConfigurationElement element) {
    addWarning(warningsToLog, message, element, null, null, null);
  }

  /**
   * Adds a warning to be logged at some later point in time. This logs the
   * identifier of the item.
   *
   * @param warningsToLog
   *            The collection of warnings to be logged; must not be
   *            <code>null</code>.
   * @param message
   *            The mesaage to log; must not be <code>null</code>.
   * @param element
   *            The element from which the warning originates; may be
   *            <code>null</code>.
   * @param id
   *            The identifier of the item for which a warning is being
   *            logged; may be <code>null</code>.
   */
  protected static final void addWarning(final List warningsToLog,
      final String message, final IConfigurationElement element,
      final String id) {
    addWarning(warningsToLog, message, element, id, null, null);
  }

  /**
   * Adds a warning to be logged at some later point in time. This logs the
   * identifier of the item, as well as an extra attribute.
   *
   * @param warningsToLog
   *            The collection of warnings to be logged; must not be
   *            <code>null</code>.
   * @param message
   *            The mesaage to log; must not be <code>null</code>.
   * @param element
   *            The element from which the warning originates; may be
   *            <code>null</code>.
   * @param id
   *            The identifier of the item for which a warning is being
   *            logged; may be <code>null</code>.
   * @param extraAttributeName
   *            The name of extra attribute to be logged; may be
   *            <code>null</code>.
   * @param extraAttributeValue
   *            The value of the extra attribute to be logged; may be
   *            <code>null</code>.
   */
  protected static final void addWarning(final List warningsToLog,
      final String message, final IConfigurationElement element,
      final String id, final String extraAttributeName,
      final String extraAttributeValue) {
    String statusMessage = message;
    if (element != null) {
      statusMessage = statusMessage
          + ": plug-in='" + element.getNamespace() + '\''; //$NON-NLS-1$
    }
    if (id != null) {
      if (element != null) {
        statusMessage = statusMessage + ',';
      } else {
        statusMessage = statusMessage + ':';
      }
      statusMessage = statusMessage + " id='" + id + '\''; //$NON-NLS-1$
    }
    if (extraAttributeName != null) {
      if ((element != null) || (id != null)) {
        statusMessage = statusMessage + ',';
      } else {
        statusMessage = statusMessage + ':';
      }
      statusMessage = statusMessage + ' ' + extraAttributeName + "='" //$NON-NLS-1$
          + extraAttributeValue + '\'';
    }

    final IStatus status = new Status(IStatus.WARNING,
        WorkbenchPlugin.PI_WORKBENCH, 0, statusMessage, null);
    warningsToLog.add(status);
  }

  /**
   * Checks that the class attribute or element exists for this element. This
   * is used for executable extensions that are being read in.
   *
   * @param configurationElement
   *            The configuration element which should contain a class
   *            attribute or a class child element; must not be
   *            <code>null</code>.
   * @param warningsToLog
   *            The list of warnings to be logged; never <code>null</code>.
   * @param message
   *            The message to log if something goes wrong; may be
   *            <code>null</code>.
   * @param id
   *            The identifier of the handle object; may be <code>null</code>.
   * @return <code>true</code> if the class attribute or element exists;
   *         <code>false</code> otherwise.
   */
  protected static final boolean checkClass(
      final IConfigurationElement configurationElement,
      final List warningsToLog, final String message, final String id) {
    // Check to see if we have a handler class.
    if ((configurationElement.getAttribute(ATT_CLASS) == null)
        && (configurationElement.getChildren(TAG_CLASS).length == 0)) {
      addWarning(warningsToLog, message, configurationElement, id);
      return false;
    }

    return true;
  }

  /**
   * Checks to see whether the configuration element represents a pulldown
   * action. This involves reading the <code>style</code> and
   * <code>pulldown</code> attributes.
   *
   * @param element
   *            The element to check; must not be <code>null</code>.
   * @return <code>true</code> if the element is a pulldown action;
   *         <code>false</code> otherwise.
   */
  protected static final boolean isPulldown(
      final IConfigurationElement element) {
    final String style = readOptional(element, ATT_STYLE);
    final boolean pulldown = readBoolean(element, ATT_PULLDOWN, false);
    return (pulldown || STYLE_PULLDOWN.equals(style));
  }

  /**
   * Logs any warnings in <code>warningsToLog</code>.
   *
   * @param warningsToLog
   *            The warnings to log; may be <code>null</code>.
   * @param message
   *            The message to include in the log entry; must not be
   *            <code>null</code>.
   */
  protected static final void logWarnings(final List warningsToLog,
      final String message) {
    // If there were any warnings, then log them now.
    if ((warningsToLog != null) && (!warningsToLog.isEmpty())) {
      final IStatus status = new MultiStatus(
          WorkbenchPlugin.PI_WORKBENCH, 0, (IStatus[]) warningsToLog
              .toArray(new IStatus[warningsToLog.size()]),
          message, null);
      WorkbenchPlugin.log(status);
    }
  }

  /**
   * Reads a boolean attribute from an element.
   *
   * @param configurationElement
   *            The configuration element from which to read the attribute;
   *            must not be <code>null</code>.
   * @param attribute
   *            The attribute to read; must not be <code>null</code>.
   * @param defaultValue
   *            The default boolean value.
   * @return The attribute's value; may be <code>null</code> if none.
   */
  protected static final boolean readBoolean(
      final IConfigurationElement configurationElement,
      final String attribute, final boolean defaultValue) {
    final String value = configurationElement.getAttribute(attribute);
    if (value == null) {
      return defaultValue;
    }

    if (defaultValue) {
      return !value.equalsIgnoreCase("false"); //$NON-NLS-1$
    }

    return value.equalsIgnoreCase("true"); //$NON-NLS-1$
  }

  /**
   * Reads an optional attribute from an element. This converts zero-length
   * strings into <code>null</code>.
   *
   * @param configurationElement
   *            The configuration element from which to read the attribute;
   *            must not be <code>null</code>.
   * @param attribute
   *            The attribute to read; must not be <code>null</code>.
   * @return The attribute's value; may be <code>null</code> if none.
   */
  protected static final String readOptional(
      final IConfigurationElement configurationElement,
      final String attribute) {
    String value = configurationElement.getAttribute(attribute);
    if ((value != null) && (value.length() == 0)) {
      value = null;
    }

    return value;
  }

  /**
   * Reads the parameterized command from a parent configuration element. This
   * is used to read the parameter sub-elements from a key element, as well as
   * the command id. Each parameter is guaranteed to be valid. If invalid
   * parameters are found, then a warning status will be appended to the
   * <code>warningsToLog</code> list. The command id is required, or a
   * warning will be logged.
   *
   * @param configurationElement
   *            The configuration element from which the parameters should be
   *            read; must not be <code>null</code>.
   * @param commandService
   *            The service providing commands for the workbench; must not be
   *            <code>null</code>.
   * @param warningsToLog
   *            The list of warnings found during parsing. Warnings found will
   *            parsing the parameters will be appended to this list. This
   *            value must not be <code>null</code>.
   * @param message
   *            The message to print if the command identifier is not present;
   *            must not be <code>null</code>.
   * @return The array of parameters found for this configuration element;
   *         <code>null</code> if none can be found.
   */
  protected static final ParameterizedCommand readParameterizedCommand(
      final IConfigurationElement configurationElement,
      final ICommandService commandService, final List warningsToLog,
      final String message, final String id) {
    final String commandId = readRequired(configurationElement,
        ATT_COMMAND_ID, warningsToLog, message, id);
    if (commandId == null) {
      return null;
    }

    final Command command = commandService.getCommand(commandId);
    final ParameterizedCommand parameterizedCommand = readParameters(
        configurationElement, warningsToLog, command);

    return parameterizedCommand;
  }

  /**
   * Reads the parameters from a parent configuration element. This is used to
   * read the parameter sub-elements from a key element. Each parameter is
   * guaranteed to be valid. If invalid parameters are found, then a warning
   * status will be appended to the <code>warningsToLog</code> list.
   *
   * @param configurationElement
   *            The configuration element from which the parameters should be
   *            read; must not be <code>null</code>.
   * @param warningsToLog
   *            The list of warnings found during parsing. Warnings found will
   *            parsing the parameters will be appended to this list. This
   *            value must not be <code>null</code>.
   * @param command
   *            The command around which the parameterization should be
   *            created; must not be <code>null</code>.
   * @return The array of parameters found for this configuration element;
   *         <code>null</code> if none can be found.
   */
  protected static final ParameterizedCommand readParameters(
      final IConfigurationElement configurationElement,
      final List warningsToLog, final Command command) {
    final IConfigurationElement[] parameterElements = configurationElement
        .getChildren(TAG_PARAMETER);
    if ((parameterElements == null) || (parameterElements.length == 0)) {
      return new ParameterizedCommand(command, null);
    }

    final Collection parameters = new ArrayList();
    for (int i = 0; i < parameterElements.length; i++) {
      final IConfigurationElement parameterElement = parameterElements[i];

      // Read out the id.
      final String id = parameterElement.getAttribute(ATT_ID);
      if ((id == null) || (id.length() == 0)) {
        // The name should never be null. This is invalid.
        addWarning(warningsToLog, "Parameters need a name", //$NON-NLS-1$
            configurationElement);
        continue;
      }

      // Find the parameter on the command.
      IParameter parameter = null;
      try {
        final IParameter[] commandParameters = command.getParameters();
        if (parameters != null) {
          for (int j = 0; j < commandParameters.length; j++) {
            final IParameter currentParameter = commandParameters[j];
            if (Util.equals(currentParameter.getId(), id)) {
              parameter = currentParameter;
              break;
            }
          }

        }
      } catch (final NotDefinedException e) {
        // This should not happen.
      }
      if (parameter == null) {
        // The name should never be null. This is invalid.
        addWarning(warningsToLog,
            "Could not find a matching parameter", //$NON-NLS-1$
            configurationElement, id);
        continue;
      }

      // Read out the value.
      final String value = parameterElement.getAttribute(ATT_VALUE);
      if ((value == null) || (value.length() == 0)) {
        // The name should never be null. This is invalid.
        addWarning(warningsToLog, "Parameters need a value", //$NON-NLS-1$
            configurationElement, id);
        continue;
      }

      parameters.add(new Parameterization(parameter, value));
    }

    if (parameters.isEmpty()) {
      return new ParameterizedCommand(command, null);
    }

    return new ParameterizedCommand(command,
        (Parameterization[]) parameters
            .toArray(new Parameterization[parameters.size()]));
  }

  /**
   * Reads a required attribute from the configuration element.
   *
   * @param configurationElement
   *            The configuration element from which to read; must not be
   *            <code>null</code>.
   * @param attribute
   *            The attribute to read; must not be <code>null</code>.
   * @param warningsToLog
   *            The list of warnings; must not be <code>null</code>.
   * @param message
   *            The warning message to use if the attribute is missing; must
   *            not be <code>null</code>.
   * @return The required attribute; may be <code>null</code> if missing.
   */
  protected static final String readRequired(
      final IConfigurationElement configurationElement,
      final String attribute, final List warningsToLog,
      final String message) {
    return readRequired(configurationElement, attribute, warningsToLog,
        message, null);
  }

  /**
   * Reads a required attribute from the configuration element. This logs the
   * identifier of the item if this required element cannot be found.
   *
   * @param configurationElement
   *            The configuration element from which to read; must not be
   *            <code>null</code>.
   * @param attribute
   *            The attribute to read; must not be <code>null</code>.
   * @param warningsToLog
   *            The list of warnings; must not be <code>null</code>.
   * @param message
   *            The warning message to use if the attribute is missing; must
   *            not be <code>null</code>.
   * @param id
   *            The identifier of the element for which this is a required
   *            attribute; may be <code>null</code>.
   * @return The required attribute; may be <code>null</code> if missing.
   */
  protected static final String readRequired(
      final IConfigurationElement configurationElement,
      final String attribute, final List warningsToLog,
      final String message, final String id) {
    final String value = configurationElement.getAttribute(attribute);
    if ((value == null) || (value.length() == 0)) {
      addWarning(warningsToLog, message, configurationElement, id);
      return null;
    }

    return value;
  }

  /**
   * Reads a <code>when</code> child element from the given configuration
   * element. Warnings will be appended to <code>warningsToLog</code>.
   *
   * @param parentElement
   *            The configuration element which might have a <code>when</code>
   *            element as a child; never <code>null</code>.
   * @param whenElementName
   *            The name of the when element to find; never <code>null</code>.
   * @param id
   *            The identifier of the menu element whose <code>when</code>
   *            expression is being read; never <code>null</code>.
   * @param warningsToLog
   *            The list of warnings while parsing the extension point; never
   *            <code>null</code>.
   * @return The <code>when</code> expression for the
   *         <code>configurationElement</code>, if any; otherwise,
   *         <code>null</code>.
   */
  protected static final Expression readWhenElement(
      final IConfigurationElement parentElement,
      final String whenElementName, final String id,
      final List warningsToLog) {
    // Check to see if we have an when expression.
    final IConfigurationElement[] whenElements = parentElement
        .getChildren(whenElementName);
    Expression whenExpression = null;
    if (whenElements.length > 0) {
      // Check if we have too many when elements.
      if (whenElements.length > 1) {
        // There should only be one when element
        addWarning(warningsToLog,
            "There should only be one when element", parentElement, //$NON-NLS-1$
            id, "whenElementName", //$NON-NLS-1$
            whenElementName);
        return ERROR_EXPRESSION;
      }

      final IConfigurationElement whenElement = whenElements[0];
      final IConfigurationElement[] expressionElements = whenElement
          .getChildren();
      if (expressionElements.length > 0) {
        // Check if we have too many expression elements
        if (expressionElements.length > 1) {
          // There should only be one expression element
          addWarning(
              warningsToLog,
              "There should only be one expression element", parentElement, //$NON-NLS-1$
              id, "whenElementName", //$NON-NLS-1$
              whenElementName);
          return ERROR_EXPRESSION;
        }

        // Convert the activeWhen element into an expression.
        final ElementHandler elementHandler = ElementHandler
            .getDefault();
        final ExpressionConverter converter = ExpressionConverter
            .getDefault();
        final IConfigurationElement expressionElement = expressionElements[0];
        try {
          whenExpression = elementHandler.create(converter,
              expressionElement);
        } catch (final CoreException e) {
          // There when expression could not be created.
          addWarning(
              warningsToLog,
              "Problem creating when element", //$NON-NLS-1$
              parentElement, id,
              "whenElementName", whenElementName); //$NON-NLS-1$
          return ERROR_EXPRESSION;
        }
      }
    }

    return whenExpression;
  }

  /**
   * The registry change listener for this class.
   */
  private final IRegistryChangeListener registryChangeListener;

  /**
   * Whether the preference and registry change listeners have been attached
   * yet.
   */
  protected boolean registryListenerAttached = false;

  /**
   * Constructs a new instance of {@link RegistryPersistence}. A registry
   * change listener is created.
   */
  protected RegistryPersistence() {
    registryChangeListener = new IRegistryChangeListener() {
      public final void registryChanged(final IRegistryChangeEvent event) {
        if (isChangeImportant(event)) {
          Display.getDefault().asyncExec(new Runnable() {
            public final void run() {
              read();
            }
          });
        }
      }
    };
  }

  /**
   * Detaches the registry change listener from the registry.
   */
  public void dispose() {
    final IExtensionRegistry registry = Platform.getExtensionRegistry();
    registry.removeRegistryChangeListener(registryChangeListener);
    registryListenerAttached = false;
  }

  /**
   * Checks whether the registry change could affect this persistence class.
   *
   * @param event
   *            The event indicating the registry change; must not be
   *            <code>null</code>.
   * @return <code>true</code> if the persistence instance is affected by
   *         this change; <code>false</code> otherwise.
   */
  protected abstract boolean isChangeImportant(
      final IRegistryChangeEvent event);

  /**
   * Reads the various elements from the registry. Subclasses should extend,
   * but must not override.
   */
  protected void read() {
    if (!registryListenerAttached) {
      final IExtensionRegistry registry = Platform.getExtensionRegistry();
      registry.addRegistryChangeListener(registryChangeListener);
      registryListenerAttached = true;
    }
  }
}
TOP

Related Classes of org.eclipse.ui.internal.services.RegistryPersistence

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.