Package org.springframework.ide.eclipse.beans.core.metadata.internal.model

Source Code of org.springframework.ide.eclipse.beans.core.metadata.internal.model.BeanMetadataBuilderJob

/*******************************************************************************
* Copyright (c) 2010 Spring IDE Developers
* 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:
*     Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.beans.core.metadata.internal.model;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.ui.progress.IProgressConstants;
import org.springframework.ide.eclipse.beans.core.BeansCoreImages;
import org.springframework.ide.eclipse.beans.core.BeansCorePlugin;
import org.springframework.ide.eclipse.beans.core.internal.model.BeansModel;
import org.springframework.ide.eclipse.beans.core.internal.model.BeansModelUtils;
import org.springframework.ide.eclipse.beans.core.metadata.BeansMetadataPlugin;
import org.springframework.ide.eclipse.beans.core.metadata.model.IBeanMetadata;
import org.springframework.ide.eclipse.beans.core.metadata.model.IBeanMetadataProvider;
import org.springframework.ide.eclipse.beans.core.metadata.model.IMethodMetadata;
import org.springframework.ide.eclipse.beans.core.model.IBean;
import org.springframework.ide.eclipse.beans.core.model.IBeanProperty;
import org.springframework.ide.eclipse.beans.core.model.IBeansConfig;
import org.springframework.ide.eclipse.beans.core.model.IBeansProject;
import org.springframework.ide.eclipse.core.model.ModelChangeEvent.Type;

/**
* {@link Job} implementation that handles loading and attaching {@link IBeanMetadata} for {@link IBeansConfig}.
* @author Christian Dupuis
* @since 2.0.5
*/
public class BeanMetadataBuilderJob extends Job {

  /** The metadataProvider element in the extension point contribution */
  private static final String METADATA_PROVIDER_ELEMENT = "metadataProvider";

  /** The class attribute in the extension point contribution */
  private static final String CLASS_ATTRIBUTE = "class";

  /** The id of the metadata providers extension point */
  public static final String META_DATA_PROVIDERS_EXTENSION_POINT = BeansMetadataPlugin.PLUGIN_ID
      + ".metadataproviders";

  /** Object identifying the job family */
  private static final Object CONTENT_FAMILY = new Object();

  /** Internal cache of the affected {@link IBean}s keyed by the containing {@link IBeansConfig} */
  private Map<IBeansConfig, Set<IBean>> affectedBeans;

  /**
   * Constructor
   * @param affectedBeans the list of affected {@link IBean} keyed by a corresponding {@link IBeansConfig}.
   */
  public BeanMetadataBuilderJob(Map<IBeansConfig, Set<IBean>> affectedBeans) {
    super("Resolving Spring Meta Data");
    this.affectedBeans = affectedBeans;
    setPriority(Job.BUILD);
    setSystem(true);
    setProperty(IProgressConstants.ICON_PROPERTY, BeansCoreImages.DESC_OBJS_ANNOTATATION);
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public boolean belongsTo(Object family) {
    return CONTENT_FAMILY == family;
  }

  public boolean isCoveredBy(BeanMetadataBuilderJob other) {
    if (other.affectedBeans != null && this.affectedBeans != null) {
      Set<IBean> allBeans = new HashSet<IBean>();
      for (Set<IBean> beans : other.affectedBeans.values()) {
        allBeans.addAll(beans);
      }
      Set<IBean> allMyBeans = new HashSet<IBean>();
      for (Set<IBean> beans : this.affectedBeans.values()) {
        allMyBeans.addAll(beans);
      }
      return allBeans.containsAll(allMyBeans);
    }
    return false;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public IStatus run(IProgressMonitor monitor) {
    try {
      // Remove similar jobs from the chain
      synchronized (getClass()) {
        if (monitor.isCanceled()) {
          return Status.CANCEL_STATUS;
        }
        Job[] buildJobs = Job.getJobManager().find(CONTENT_FAMILY);
        for (int i = 0; i < buildJobs.length; i++) {
          Job curr = buildJobs[i];
          if (curr != this && curr instanceof BeanMetadataBuilderJob) {
            BeanMetadataBuilderJob job = (BeanMetadataBuilderJob) curr;
            if (job.isCoveredBy(this)) {
              curr.cancel();
            }
          }
        }
      }
      monitor.beginTask("Attaching Spring bean meta data", affectedBeans.size());

      // Reading contributed IBeanMetadataProviders from the extension point
      IBeanMetadataProvider[] providers = getMetadataProviders();
      Set<IBeansProject> projects = new LinkedHashSet<IBeansProject>();

      for (Map.Entry<IBeansConfig, Set<IBean>> entry : affectedBeans.entrySet()) {

        // Do some profiling
        long start = System.currentTimeMillis();
        IResource resource = entry.getKey().getElementResource();
        projects.add(BeansModelUtils.getParentOfClass(entry.getKey(), IBeansProject.class));

        monitor.subTask("Attaching Spring bean meta data to file [" + resource.getFullPath().toString() + "]");
        attachMetadata(entry.getKey(), entry.getValue(), monitor, providers);
        monitor.worked(1);

        if (BeanMetadataModel.DEBUG) {
          System.out.println("Attaching meta data [" + resource.getFullPath().toString() + "] took "
              + (System.currentTimeMillis() - start) + "ms");
        }
      }

      // Notify that the model has changed.
      for (IBeansProject project : projects) {
        ((BeansModel) BeansCorePlugin.getModel()).notifyListeners(project, Type.CHANGED);
      }

    }
    finally {
      affectedBeans = null;
    }
    return Status.OK_STATUS;
  }

  /**
   * Iterates over the provided list of {@link IBeanMetadataProvider}s and attaches {@link IBeanMetadata} and
   * {@link IBeanProperty}s to the given {@link IBean} instance.
   */
  protected void attachMetadata(IBeansConfig beansConfig, Set<IBean> beans, IProgressMonitor progressMonitor,
      IBeanMetadataProvider[] providers) {

    for (IBean bean : beans) {
      attachMetadataToBean(beansConfig, progressMonitor, providers, bean);
    }
  }

  /**
   * Attaches {@link IBeanMetadata} and {@link IBeanProperty} to a single {@link IBean}.
   */
  private void attachMetadataToBean(final IBeansConfig beansConfig, final IProgressMonitor progressMonitor,
      IBeanMetadataProvider[] providers, final IBean bean) {
    // Reset meta data attachment before adding
    BeansMetadataPlugin.getMetadataModel().clearBeanMetadata(bean);
    BeansMetadataPlugin.getMetadataModel().clearBeanProperties(bean);

    Set<IBeanMetadata> beanMetaData = new LinkedHashSet<IBeanMetadata>();
    Set<IMethodMetadata> methodMetaData = new LinkedHashSet<IMethodMetadata>();

    final Set<IBeanMetadata> beanMetaDataSet = new LinkedHashSet<IBeanMetadata>();
    final Set<IBeanProperty> beanProperties = new LinkedHashSet<IBeanProperty>();
    for (final IBeanMetadataProvider provider : providers) {

      // make sure third-party extensions don't crash the build
      SafeRunner.run(new ISafeRunnable() {

        public void handleException(Throwable exception) {
          // nothing to do here
        }

        public void run() throws Exception {
          beanMetaDataSet.addAll(provider.provideBeanMetadata(bean, beansConfig, progressMonitor));
          beanProperties.addAll(provider.provideBeanProperties(bean, beansConfig, progressMonitor));
        }
      });

      for (IBeanMetadata metaData : beanMetaDataSet) {
        if (metaData instanceof IMethodMetadata) {
          methodMetaData.add((IMethodMetadata) metaData);
        }
        else {
          beanMetaData.add(metaData);
        }
      }
    }
    if (beanMetaData.size() > 0 || methodMetaData.size() > 0) {
      BeansMetadataPlugin.getMetadataModel().setBeanMetadata(bean, beanMetaData, methodMetaData);
    }
    if (beanProperties.size() > 0) {
      BeansMetadataPlugin.getMetadataModel().setBeanProperties(bean, beanProperties);
    }
  }

  /**
   * Returns the {@link IBeanMetadataProvider}s contributed to the Eclipse extension point registry.
   */
  protected IBeanMetadataProvider[] getMetadataProviders() {
    List<IBeanMetadataProvider> providers = new ArrayList<IBeanMetadataProvider>();
    IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(META_DATA_PROVIDERS_EXTENSION_POINT);
    if (point != null) {
      for (IExtension extension : point.getExtensions()) {
        for (IConfigurationElement config : extension.getConfigurationElements()) {
          if (METADATA_PROVIDER_ELEMENT.equals(config.getName())
              && config.getAttribute(CLASS_ATTRIBUTE) != null) {
            try {
              Object handler = config.createExecutableExtension(CLASS_ATTRIBUTE);
              if (handler instanceof IBeanMetadataProvider) {
                IBeanMetadataProvider entityResolver = (IBeanMetadataProvider) handler;
                providers.add(entityResolver);
              }
            }
            catch (CoreException e) {
              BeansMetadataPlugin.getDefault().getLog().log(
                  new Status(IStatus.ERROR, BeansMetadataPlugin.PLUGIN_ID, 1, "Error loading metadata provider", e));
            }
          }
        }
      }
    }
    return providers.toArray(new IBeanMetadataProvider[providers.size()]);
  }

}
TOP

Related Classes of org.springframework.ide.eclipse.beans.core.metadata.internal.model.BeanMetadataBuilderJob

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.