Package org.activiti.designer.util.extension

Source Code of org.activiti.designer.util.extension.ExtensionUtil

/**
*
*/
package org.activiti.designer.util.extension;

import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.Manifest;

import org.activiti.bpmn.model.CustomProperty;
import org.activiti.bpmn.model.ServiceTask;
import org.activiti.designer.integration.palette.AbstractDefaultPaletteCustomizer;
import org.activiti.designer.integration.palette.DefaultPaletteCustomizer;
import org.activiti.designer.integration.palette.PaletteEntry;
import org.activiti.designer.integration.servicetask.AbstractCustomServiceTask;
import org.activiti.designer.integration.servicetask.CustomServiceTask;
import org.activiti.designer.integration.servicetask.CustomServiceTaskDescriptor;
import org.activiti.designer.util.eclipse.ActivitiUiUtil;
import org.activiti.designer.util.eclipse.ExtensionConstants;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.graphiti.ui.editor.DiagramEditor;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJarEntryResource;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.JarEntryDirectory;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;

/**
* Provides utilities for Extensions to the Designer.
*
* @author Tiese Barrell
* @since 0.5.1
* @version 1
*
*/
public final class ExtensionUtil {

  public static final String USER_LIBRARY_NAME_EXTENSIONS = "Activiti Designer Extensions";

  public static final String DESIGNER_EXTENSIONS_USER_LIB_PATH = "org.eclipse.jdt.USER_LIBRARY/" + USER_LIBRARY_NAME_EXTENSIONS;

  public static List<CustomServiceTaskDescriptor> providedCustomServiceTaskDescriptors;

  private static final List<String> FLAGS = new ArrayList<String>();

  private ExtensionUtil() {

  }

  public static void addProvidedCustomServiceTaskDescriptors(List<CustomServiceTaskDescriptor> descriptors) {
    if (providedCustomServiceTaskDescriptors == null)
      providedCustomServiceTaskDescriptors = new ArrayList<CustomServiceTaskDescriptor>();
    providedCustomServiceTaskDescriptors.addAll(descriptors);
  }

  public static final Set<PaletteEntry> getDisabledPaletteEntries(IProject project) {

    Set<PaletteEntry> result = new HashSet<PaletteEntry>();

    // Determine the project
    IJavaProject javaProject = null;
    try {
      javaProject = (IJavaProject) project.getNature(JavaCore.NATURE_ID);
    } catch (CoreException e) {
      // skip, not a Java project
    }

    if (javaProject != null) {

      try {

        // Get the container for the designer extensions. This is the
        // predefined user library linking to the extension libraries
        final IClasspathContainer userLibraryContainer = JavaCore.getClasspathContainer(new Path(DESIGNER_EXTENSIONS_USER_LIB_PATH), javaProject);

        // Get a list of the classpath entries in the container. Each of
        // these represents one jar containing zero or more designer
        // extensions
        final IClasspathEntry[] extensionJars = userLibraryContainer.getClasspathEntries();

        // If there are jars, inspect them; otherwise return because
        // there are no extensions
        if (extensionJars.length > 0) {

          for (final IClasspathEntry classpathEntry : extensionJars) {

            // Only check entries of the correct kind
            if (classpathEntry.getEntryKind() == 1 && classpathEntry.getContentKind() == 2) {

              final IPackageFragmentRoot packageFragmentRoot = javaProject.getPackageFragmentRoot(classpathEntry.getPath().toString());

              // Create a JarClassLoader to load any classes we
              // find for this extension
              final JarClassLoader cl = new JarClassLoader(packageFragmentRoot.getPath().toPortableString());

              // Inspect the jar by scanning its classpath and looking for
              // classes that implement
              // CustomServiceTask
              final IJavaElement[] javaElements = packageFragmentRoot.getChildren();
              for (final IJavaElement javaElement : javaElements) {
                if (javaElement.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
                  IPackageFragment fragment = (IPackageFragment) javaElement;
                  if (fragment.containsJavaResources()) {
                    final IClassFile[] classFiles = fragment.getClassFiles();
                    for (final IClassFile classFile : classFiles) {
                      if (classFile.isClass()) {

                        final IType type = classFile.getType();
                        if (!isConcretePaletteCustomizer(type)) {
                          continue;
                        }

                        try {
                          Class<DefaultPaletteCustomizer> clazz = (Class<DefaultPaletteCustomizer>) cl.loadClass(type.getFullyQualifiedName());

                          if (DefaultPaletteCustomizer.class.isAssignableFrom(clazz)) {
                            try {
                              DefaultPaletteCustomizer DefaultPaletteCustomizer = (DefaultPaletteCustomizer) clazz.newInstance();
                              // Add this DefaultPaletteCustomizer to the result
                              result.addAll(DefaultPaletteCustomizer.disablePaletteEntries());
                            } catch (InstantiationException e) {
                              // TODO Auto-generated catch block
                              e.printStackTrace();
                            } catch (IllegalAccessException e) {
                              // TODO Auto-generated catch block
                              e.printStackTrace();
                            }
                          }
                        } catch (ClassNotFoundException e) {
                          e.printStackTrace();
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      } catch (JavaModelException e) {
        // TODO: test when this exception occurs: if there is no user
        // lib for example?
        e.printStackTrace();
      }

    }

    return result;
  }

  private static boolean isConcreteCustomService(IType type) {

    boolean customserviceFound = containsAbstractClassOrInterface(type, AbstractCustomServiceTask.class, CustomServiceTask.class);

    try {
      if (customserviceFound && !Modifier.isAbstract(type.getFlags())) {
        customserviceFound = true;
      } else {
        customserviceFound = false;
      }
    } catch (JavaModelException e) {
      customserviceFound = false;
      e.printStackTrace();
    }

    return customserviceFound;

  }

  private static boolean isConcretePaletteCustomizer(IType type) {

    boolean paletteCustomizerFound = containsAbstractClassOrInterface(type, AbstractDefaultPaletteCustomizer.class, DefaultPaletteCustomizer.class);

    try {
      if (paletteCustomizerFound && !Modifier.isAbstract(type.getFlags())) {
        paletteCustomizerFound = true;
      } else {
        paletteCustomizerFound = false;
      }
    } catch (JavaModelException e) {
      paletteCustomizerFound = false;
      e.printStackTrace();
    }

    return paletteCustomizerFound;

  }

  // TODO: utilize type hierarchy in efficient manner
  private static boolean containsAbstractClassOrInterface(IType type, Class targetAbstractClass, Class targetInterface) {

    boolean result = false;

    try {
      // 1. Check whether the super classname of the type matches the abstract
      // superclass we favor
      // 2. Check whether the type implements the interface itself
      // 3. If the type has *other* superclasses than the one we favor,
      // recursively inspect the hierarchy
      // using
      // the same method
      if (targetAbstractClass.getCanonicalName().equalsIgnoreCase(type.getSuperclassName())) {
        result = true;
      } else if (type.getSuperInterfaceNames() != null && type.getSuperInterfaceNames().length > 0) {
        for (String interfaceName : type.getSuperInterfaceNames()) {
          if (targetInterface.getCanonicalName().equalsIgnoreCase(interfaceName)) {
            result = true;
          }
        }
      }
      // } else if (type.getSuperclassName() != null) {
      // result =
      // containsAbstractClassOrInterface(hierarchy.getSuperclass(type),
      // targetAbstractClass, targetInterface);
      // }

    } catch (Exception e) {
      result = false;
    }

    return result;

  }

  /**
   * Wraps the property id for the provided service tasks.
   *
   * @param serviceTask
   *          the parent task the property belongs to
   * @param propertyId
   *          the id of the property to wrap
   * @return the wrapped id
   */
  public static final String wrapCustomPropertyId(final ServiceTask serviceTask, final String propertyId) {
    return serviceTask.getId() + ExtensionConstants.CUSTOM_PROPERTY_ID_SEPARATOR + propertyId;
  }

  /**
   * Unwraps the provided property id string.
   *
   * @param wrappedCustomPropertyId
   *          the id string to unwrap
   * @return the unwrapped id
   */
  public static final String upWrapCustomPropertyId(final String wrappedCustomPropertyId) {
    return StringUtils.substringAfter(wrappedCustomPropertyId, ExtensionConstants.CUSTOM_PROPERTY_ID_SEPARATOR);
  }

  /**
   * Determines whether the provided business object is a custom service task.
   *
   * @param bo
   *          the business object
   * @return true if the business object is a custom service task, false
   *         otherwise
   */
  public static final boolean isCustomServiceTask(final Object bo) {
    boolean result = false;
    if (bo instanceof ServiceTask) {
      final ServiceTask serviceTask = (ServiceTask) bo;
      return StringUtils.isNotEmpty(serviceTask.getExtensionId());
    }
    return result;
  }

  /**
   * Gets the {@link CustomProperty} identified by the provided name from the
   * serviceTask.
   *
   * @param serviceTask
   *          the servicetask that holds the custom property
   * @param propertyName
   *          the name of the property
   * @return the {@link CustomProperty} found or null if no property was found
   */
  public static final CustomProperty getCustomProperty(final ServiceTask serviceTask, final String propertyName) {
    CustomProperty result = null;
    for (final CustomProperty customProperty : serviceTask.getCustomProperties()) {
      if (propertyName.equals(customProperty.getName())) {
        result = customProperty;
        break;
      }
    }
    return result;
  }

  /**
   * Determines whether the {@link CustomProperty} identified by the provided
   * name is held by the serviceTask.
   *
   * @param serviceTask
   *          the servicetask that holds the custom property
   * @param propertyName
   *          the name of the property
   * @return true if the serviceTask has the property, false otherwise
   */
  public static final boolean hasCustomProperty(final ServiceTask serviceTask, final String propertyName) {
    boolean result = false;
    for (final CustomProperty customProperty : serviceTask.getCustomProperties()) {
      if (propertyName.equals(customProperty.getName())) {
        result = true;
        break;
      }
    }

    return result;
  }

  /**
   * Gets a list of {@link CustomServiceTask} objects based on the
   * {@link TabbedPropertySheetPage} provided.
   *
   * @param tabbedPropertySheetPage
   *          the property sheet page linked to a diagram in a project that has
   *          {@link CustomServiceTask}s defined
   * @return a list of all {@link CustomServiceTask}s or an empty list if none
   *         were found
   */
  public static List<CustomServiceTask> getCustomServiceTasks(final TabbedPropertySheetPage tabbedPropertySheetPage) {

    // Determine the part the property sheet page is in
    final IWorkbenchPart part = tabbedPropertySheetPage.getSite().getWorkbenchWindow().getPartService().getActivePart();

    // If the part is a diagram editor, get the project from the diagram
    if (part instanceof DiagramEditor) {
      final DiagramEditor editor = (DiagramEditor) part;
      final IProject project = ActivitiUiUtil.getProjectFromDiagram(editor.getDiagramTypeProvider().getDiagram());

      // Determine the custom service tasks using the project found
      return getCustomServiceTasks(project);
    }

    return null;
  }

  /**
   * Gets a list of {@link CustomServiceTask} objects based on the
   * {@link IProject} provided.
   *
   * @param project
   *          the project that has {@link CustomServiceTask}s defined
   * @return a list of all {@link CustomServiceTask}s or an empty list if none
   *         were found
   */
  public static List<CustomServiceTask> getCustomServiceTasks(final IProject project) {

    List<CustomServiceTask> result = new ArrayList<CustomServiceTask>();

    // Determine the project
    IJavaProject javaProject = null;
    try {
      javaProject = (IJavaProject) project.getNature(JavaCore.NATURE_ID);
    } catch (CoreException e) {
      // skip, not a Java project
    }

    if (javaProject != null) {

      // get the contexts first
      final List<CustomServiceTaskContext> cstContexts = getCustomServiceTaskContexts(project);

      // extract custom service tasks from the contexts
      for (final CustomServiceTaskContext customServiceTaskContext : cstContexts) {
        result.add(customServiceTaskContext.getServiceTask());
      }
    }

    return result;
  }

  /**
   * Gets a list of {@link CustomServiceTaskContext} objects based on the
   * {@link IProject} provided.
   *
   * @param project
   *          the project that has {@link CustomServiceTask}s defined
   * @return a list containing the context of each {@link CustomServiceTask}
   *         object found or an empty list if {@link CustomServiceTask}s were
   *         found were found
   */
  public static List<CustomServiceTaskContext> getCustomServiceTaskContexts(final IProject project) {

    List<CustomServiceTaskContext> result = new ArrayList<CustomServiceTaskContext>();

    addToCustomServiceTasks(result);

    IJavaProject javaProject = null;
    try {
      javaProject = (IJavaProject) project.getNature(JavaCore.NATURE_ID);
    } catch (CoreException e) {
      // skip, not a Java project
    }

    if (javaProject != null) {

      try {

        // Get the container for the designer extensions. This is the
        // predefined user library linking to the extension libraries
        final IClasspathContainer userLibraryContainer = JavaCore.getClasspathContainer(new Path(DESIGNER_EXTENSIONS_USER_LIB_PATH), javaProject);

        // Get a list of the classpath entries in the container. Each of
        // these represents one jar containing zero or more designer
        // extensions
        final IClasspathEntry[] extensionJars = userLibraryContainer.getClasspathEntries();

        // If there are jars, inspect them; otherwise return because
        // there are no extensions
        if (extensionJars.length > 0) {

          for (final IClasspathEntry classpathEntry : extensionJars) {

            // Only check entries of the correct kind
            if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY && classpathEntry.getContentKind() == IPackageFragmentRoot.K_BINARY) {

              final IPackageFragmentRoot packageFragmentRoot = javaProject.getPackageFragmentRoot(classpathEntry.getPath().toString());

              // Guard against JARs that are not open,
              // http://jira.codehaus.org/browse/ACT-1445
              if (!packageFragmentRoot.isOpen()) {
                final String exceptionMessage = String
                        .format("There was an error when processing an extension to Activiti Designer. The extension at location '%s' is not open. Please make sure it is not installed inside the Eclipse workspace.",
                                classpathEntry.getPath().toString());
                showExtensionExceptionMessageIfNotFlagged(exceptionMessage, packageFragmentRoot);
                continue;
              }

              // Determine the name of the extension
              String extensionName = null;
              // Extract the manifest and look for the
              // CustomServiceTask.MANIFEST_EXTENSION_NAME
              // property
              final Manifest manifest = extractManifest(packageFragmentRoot);
              if (manifest != null) {
                extensionName = manifest.getMainAttributes().getValue(CustomServiceTask.MANIFEST_EXTENSION_NAME);
              }
              // If there is no manifest or the property wasn't
              // defined, use the jar's name as extension name
              // instead
              if (extensionName == null) {
                extensionName = classpathEntry.getPath().lastSegment();
              }

              // Create a JarClassLoader to load any classes we
              // find for this extension

              final JarClassLoader cl = new JarClassLoader(packageFragmentRoot.getPath().toPortableString());

              // Inspect the jar by scanning its classpath and
              // looking for classes that implement
              // CustomServiceTask
              final IJavaElement[] javaElements = packageFragmentRoot.getChildren();
              for (final IJavaElement javaElement : javaElements) {
                if (javaElement.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
                  IPackageFragment fragment = (IPackageFragment) javaElement;
                  if (fragment.containsJavaResources()) {
                    final IClassFile[] classFiles = fragment.getClassFiles();
                    for (final IClassFile classFile : classFiles) {
                      if (classFile.isClass()) {

                        final IType type = classFile.getType();

                        if (!isConcreteCustomService(type)) {
                          continue;
                        }
                        // if (type.getFullyQualifiedName() !=
                        // "com.atosorigin.esuite.editors.servicetasks.ESuiteEndNode")
                        // {
                        // continue;
                        // }
                        try {
                          Class<CustomServiceTask> clazz = (Class<CustomServiceTask>) cl.loadClass(type.getFullyQualifiedName());

                          // Filter if the class is
                          // abstract: this probably
                          // means it is extended by
                          // concrete classes in the
                          // extension and will have
                          // any properties applied in
                          // that way; we can't
                          // instantiate the class
                          // anyway
                          if (!Modifier.isAbstract(clazz.getModifiers()) && CustomServiceTask.class.isAssignableFrom(clazz)) {
                            try {
                              CustomServiceTask customServiceTask = (CustomServiceTask) clazz.newInstance();
                              // Add this
                              // CustomServiceTask
                              // to
                              // the result,
                              // wrapped
                              // in its context
                              result.add(new CustomServiceTaskContextImpl(customServiceTask, extensionName, classpathEntry.getPath().toPortableString()));

                            } catch (InstantiationException e) {
                              // TODO
                              // Auto-generated
                              // catch block
                              e.printStackTrace();
                            } catch (IllegalAccessException e) {
                              // TODO
                              // Auto-generated
                              // catch block
                              e.printStackTrace();
                            }

                          }
                        } catch (ClassNotFoundException e) {
                          e.printStackTrace();
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      } catch (JavaModelException e) {
        showExtensionExceptionMessage(String.format("There was a technical error when processing an extension to Activiti Designer: %s", e.getMessage()));
        e.printStackTrace();
      }
    }

    return result;
  }

  private static void showExtensionExceptionMessageIfNotFlagged(final String detailMessage, final IPackageFragmentRoot packageFragmentRoot) {
    final String flagKey = packageFragmentRoot.getPath().toPortableString();
    if (!FLAGS.contains(flagKey)) {
      FLAGS.add(flagKey);
      showExtensionExceptionMessage(detailMessage);
    }
  }
  private static void showExtensionExceptionMessage(final String detailMessage) {
    MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), "Error in extension", detailMessage);
  }

  private static void addToCustomServiceTasks(List<CustomServiceTaskContext> result) {
    if (providedCustomServiceTaskDescriptors != null) {
      for (CustomServiceTaskDescriptor dscr : providedCustomServiceTaskDescriptors) {
        Class< ? extends CustomServiceTask> clazz = dscr.getClazz();
        if (clazz != null && !Modifier.isAbstract(clazz.getModifiers()) && CustomServiceTask.class.isAssignableFrom(clazz)) {
          try {
            CustomServiceTask customServiceTask = (CustomServiceTask) clazz.newInstance();
            result.add(new CustomServiceTaskContextImpl(customServiceTask, dscr.getExtensionName(), dscr.getExtensionJarPath()));
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }
    }
  }

  /**
   * @param packageFragmentRoot
   * @throws JavaModelException
   * @throws CoreException
   */
  @SuppressWarnings("restriction")
  private static Manifest extractManifest(IPackageFragmentRoot packageFragmentRoot) throws JavaModelException {

    Manifest result = null;
    final Object[] nonJavaResources = packageFragmentRoot.getNonJavaResources();

    for (Object obj : nonJavaResources) {
      if (obj instanceof JarEntryDirectory) {
        final JarEntryDirectory jarEntryDirectory = (JarEntryDirectory) obj;
        final IJarEntryResource[] jarEntryResources = jarEntryDirectory.getChildren();
        for (IJarEntryResource jarEntryResource : jarEntryResources) {
          if ("MANIFEST.MF".equals(jarEntryResource.getName())) {
            try {
              final InputStream stream = jarEntryResource.getContents();
              result = new Manifest(stream);
            } catch (Exception e) {
              // no manifest as result
            }
          }
        }
      }
    }
    return result;
  }

}
TOP

Related Classes of org.activiti.designer.util.extension.ExtensionUtil

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.