org.eclipse.m2e.internal.discovery.MavenDiscoveryService.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.m2e.internal.discovery.MavenDiscoveryService.java

Source

/*******************************************************************************
 * Copyright (c) 2011 Sonatype, Inc.
 * 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:
 *      Sonatype, Inc. - initial API and implementation
 *******************************************************************************/

package org.eclipse.m2e.internal.discovery;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.equinox.internal.p2.discovery.Catalog;
import org.eclipse.equinox.internal.p2.discovery.model.CatalogItem;
import org.eclipse.equinox.internal.p2.ui.discovery.wizards.Messages;
import org.eclipse.equinox.p2.core.IProvisioningAgent;
import org.eclipse.equinox.p2.engine.IProfile;
import org.eclipse.equinox.p2.engine.IProfileRegistry;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.query.IQuery;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.ui.ProvisioningUI;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.statushandlers.StatusManager;

import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.project.MavenProject;

import org.eclipse.m2e.core.MavenPlugin;
import org.eclipse.m2e.core.embedder.ICallable;
import org.eclipse.m2e.core.embedder.IMavenExecutionContext;
import org.eclipse.m2e.core.internal.lifecyclemapping.LifecycleMappingFactory;
import org.eclipse.m2e.core.internal.lifecyclemapping.LifecycleMappingResult;
import org.eclipse.m2e.core.internal.lifecyclemapping.MappingMetadataSource;
import org.eclipse.m2e.core.internal.lifecyclemapping.discovery.ILifecycleMappingRequirement;
import org.eclipse.m2e.core.internal.lifecyclemapping.discovery.IMavenDiscovery;
import org.eclipse.m2e.core.internal.lifecyclemapping.discovery.IMavenDiscoveryProposal;
import org.eclipse.m2e.core.internal.lifecyclemapping.discovery.MojoExecutionMappingConfiguration;
import org.eclipse.m2e.core.internal.lifecyclemapping.discovery.PackagingTypeMappingConfiguration;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadata;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.LifecycleMappingMetadataSource;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.PluginExecutionMetadata;
import org.eclipse.m2e.core.lifecyclemapping.model.IPluginExecutionMetadata;
import org.eclipse.m2e.core.lifecyclemapping.model.PluginExecutionAction;
import org.eclipse.m2e.core.project.configurator.MojoExecutionKey;
import org.eclipse.m2e.core.ui.internal.wizards.IMavenDiscoveryUI;
import org.eclipse.m2e.internal.discovery.operation.MavenDiscoveryInstallOperation;
import org.eclipse.m2e.internal.discovery.wizards.MavenDiscoveryUi;

@SuppressWarnings({ "restriction", "rawtypes" })
public class MavenDiscoveryService implements IMavenDiscoveryUI, IMavenDiscovery, ServiceFactory {
    private static final Logger log = LoggerFactory.getLogger(MavenDiscoveryService.class);

    public static class CatalogItemCacheEntry {
        private final CatalogItem item;

        private final LifecycleMappingMetadataSource metadataSource;

        private final List<String> projectConfigurators;

        private final List<String> mappingStrategies;

        public CatalogItemCacheEntry(CatalogItem item, LifecycleMappingMetadataSource metadataSource,
                List<String> projectConfigurators, List<String> mappingStrategies) {
            this.item = item;
            this.metadataSource = metadataSource;
            this.projectConfigurators = projectConfigurators;
            this.mappingStrategies = mappingStrategies;
        }

        public CatalogItem getItem() {
            return item;
        }

        public LifecycleMappingMetadataSource getMetadataSource() {
            return metadataSource;
        }

        public List<String> getProjectConfigurators() {
            return projectConfigurators;
        }

        public List<String> getMappingStrategies() {
            return mappingStrategies;
        }
    }

    private List<CatalogItemCacheEntry> items;

    public MavenDiscoveryService() {
        this(true);
    }

    public MavenDiscoveryService(boolean factory) {
    }

    public Map<ILifecycleMappingRequirement, List<IMavenDiscoveryProposal>> discover(
            final MavenProject mavenProject, final List<MojoExecution> mojoExecutions,
            final List<IMavenDiscoveryProposal> preselected, final IProgressMonitor monitor) throws CoreException {

        if (items == null) {
            items = new ArrayList<MavenDiscoveryService.CatalogItemCacheEntry>();

            Catalog catalog = MavenDiscovery.getCatalog();
            IStatus status = catalog.performDiscovery(monitor);

            if (!status.isOK()) {
                log.error(status.toString());
                return Collections.emptyMap();
            }

            IProvisioningAgent p2agent = ProvisioningUI.getDefaultUI().getSession().getProvisioningAgent();
            IProfileRegistry profRegistry = (IProfileRegistry) p2agent.getService(IProfileRegistry.SERVICE_NAME);
            IProfile profile = profRegistry.getProfile(IProfileRegistry.SELF);

            for (CatalogItem item : catalog.getItems()) {
                LifecycleMappingMetadataSource metadataSource = MavenDiscovery
                        .getLifecycleMappingMetadataSource(item);
                List<String> projectConfigurators = new ArrayList<String>();
                List<String> mappingStrategies = new ArrayList<String>();
                MavenDiscovery.getProvidedProjectConfigurators(item, projectConfigurators, mappingStrategies);
                if (metadataSource != null && !itemInstalled(profile, item, monitor)) {
                    addCatalogItem(item, metadataSource, projectConfigurators, mappingStrategies);
                }
            }
            catalog.dispose();
        }

        return MavenPlugin.getMaven()
                .execute(new ICallable<Map<ILifecycleMappingRequirement, List<IMavenDiscoveryProposal>>>() {
                    public Map<ILifecycleMappingRequirement, List<IMavenDiscoveryProposal>> call(
                            IMavenExecutionContext context, IProgressMonitor monitor) throws CoreException {
                        return discover0(mavenProject, mojoExecutions, preselected, monitor);
                    }
                }, monitor);
    }

    /*package*/Map<ILifecycleMappingRequirement, List<IMavenDiscoveryProposal>> discover0(MavenProject mavenProject,
            List<MojoExecution> mojoExecutions, List<IMavenDiscoveryProposal> preselected, IProgressMonitor monitor)
            throws CoreException {
        Map<ILifecycleMappingRequirement, List<IMavenDiscoveryProposal>> proposals = new LinkedHashMap<ILifecycleMappingRequirement, List<IMavenDiscoveryProposal>>();

        Collection<CatalogItem> selectedItems = toCatalogItems(preselected);
        List<LifecycleMappingMetadataSource> selectedSources = toMetadataSources(preselected);

        for (CatalogItemCacheEntry itemEntry : items) {
            CatalogItem item = itemEntry.getItem();
            LifecycleMappingMetadataSource src = itemEntry.getMetadataSource();

            boolean preselectItem = false;
            for (CatalogItem selectedItem : selectedItems) {
                if (selectedItem.getSiteUrl().equals(item.getSiteUrl())
                        && selectedItem.getInstallableUnits().equals(item.getInstallableUnits())) {
                    preselectItem = true;
                    break;
                }
            }

            if (src != null) {
                log.debug("Considering catalog item '{}'", item.getName()); //$NON-NLS-1$

                src.setSource(item);

                LifecycleMappingResult mappingResult = new LifecycleMappingResult();

                List<LifecycleMappingMetadataSource> sources = new ArrayList<LifecycleMappingMetadataSource>(
                        selectedSources);
                if (!preselectItem) {
                    sources.add(src);
                }

                List<MappingMetadataSource> metadataSources = LifecycleMappingFactory
                        .getProjectMetadataSources(mavenProject, sources, mojoExecutions, false, monitor);

                LifecycleMappingFactory.calculateEffectiveLifecycleMappingMetadata(mappingResult, metadataSources,
                        mavenProject, mojoExecutions, false, monitor);

                LifecycleMappingMetadata lifecycleMappingMetadata = mappingResult.getLifecycleMappingMetadata();
                if (lifecycleMappingMetadata != null) {
                    IMavenDiscoveryProposal proposal = getProposal(lifecycleMappingMetadata.getSource());
                    if (proposal != null) {
                        put(proposals, new PackagingTypeMappingConfiguration.PackagingTypeMappingRequirement(
                                mavenProject.getPackaging()), proposal);
                    } else if (!LifecycleMappingFactory.getLifecycleMappingExtensions()
                            .containsKey(lifecycleMappingMetadata.getLifecycleMappingId())) {
                        if (itemEntry.getMappingStrategies()
                                .contains(lifecycleMappingMetadata.getLifecycleMappingId())) {
                            put(proposals,
                                    new PackagingTypeMappingConfiguration.LifecycleStrategyMappingRequirement(
                                            lifecycleMappingMetadata.getPackagingType(),
                                            lifecycleMappingMetadata.getLifecycleMappingId()),
                                    new InstallCatalogItemMavenDiscoveryProposal(item));
                        }
                    }
                }

                for (Map.Entry<MojoExecutionKey, List<IPluginExecutionMetadata>> entry : mappingResult
                        .getMojoExecutionMapping().entrySet()) {
                    if (entry.getValue() != null) {
                        for (IPluginExecutionMetadata executionMapping : entry.getValue()) {
                            log.debug("mapping proposal {} => {}", entry.getKey().toString(), //$NON-NLS-1$
                                    executionMapping.getAction().toString());
                            IMavenDiscoveryProposal proposal = getProposal(
                                    ((PluginExecutionMetadata) executionMapping).getSource());
                            if (proposal != null) {
                                // assumes installation of mapping proposal installs all required project configurators 
                                put(proposals,
                                        new MojoExecutionMappingConfiguration.MojoExecutionMappingRequirement(
                                                entry.getKey()),
                                        proposal);
                            } else if (executionMapping.getAction() == PluginExecutionAction.configurator) {
                                // we have <configurator/> mapping from pom.xml
                                String configuratorId = LifecycleMappingFactory
                                        .getProjectConfiguratorId(executionMapping);
                                if (!LifecycleMappingFactory.getProjectConfiguratorExtensions()
                                        .containsKey(configuratorId)) {
                                    // User Story.
                                    // Project pom.xml explicitly specifies lifecycle mapping strategy implementation, 
                                    // but the implementation is not currently installed. As a user I expect m2e to search 
                                    // marketplace for the implementation and offer installation if available

                                    if (itemEntry.getProjectConfigurators().contains(configuratorId)) {
                                        put(proposals,
                                                new MojoExecutionMappingConfiguration.ProjectConfiguratorMappingRequirement(
                                                        entry.getKey(), configuratorId),
                                                new InstallCatalogItemMavenDiscoveryProposal(item));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        return proposals;
    }

    /**
     * Returns true if all IUs specified in the catalog item are installed in the profile
     */
    public boolean itemInstalled(IProfile profile, CatalogItem item, IProgressMonitor monitor) {
        if (profile == null) {
            return false;
        }

        List<IQuery<IInstallableUnit>> queries = new ArrayList<IQuery<IInstallableUnit>>();

        for (String iuId : item.getInstallableUnits()) {
            queries.add(QueryUtil.createIUQuery(iuId));
        }

        IQueryResult<IInstallableUnit> result = profile.query(QueryUtil.createCompoundQuery(queries, true),
                monitor);

        return !result.isEmpty();
    }

    public void addCatalogItem(CatalogItem item, LifecycleMappingMetadataSource metadataSource,
            List<String> projectConfigurators, List<String> mappingStrategies) {
        if (items == null) {
            // for tests
            items = new ArrayList<MavenDiscoveryService.CatalogItemCacheEntry>();
        }
        items.add(new CatalogItemCacheEntry(item, metadataSource, projectConfigurators, mappingStrategies));
    }

    private IMavenDiscoveryProposal getProposal(LifecycleMappingMetadataSource src) {
        if (src == null) {
            return null;
        }
        if (src.getSource() instanceof CatalogItem) {
            return new InstallCatalogItemMavenDiscoveryProposal((CatalogItem) src.getSource());
        }
        return null;
    }

    private List<LifecycleMappingMetadataSource> toMetadataSources(List<IMavenDiscoveryProposal> proposals) {
        List<LifecycleMappingMetadataSource> sources = new ArrayList<LifecycleMappingMetadataSource>();
        for (IMavenDiscoveryProposal proposal : proposals) {
            if (proposal instanceof InstallCatalogItemMavenDiscoveryProposal) {
                CatalogItem catalogItem = ((InstallCatalogItemMavenDiscoveryProposal) proposal).getCatalogItem();
                LifecycleMappingMetadataSource source = MavenDiscovery
                        .getLifecycleMappingMetadataSource(catalogItem);
                source.setSource(catalogItem);
                sources.add(source);
            }
        }
        return sources;
    }

    private void put(Map<ILifecycleMappingRequirement, List<IMavenDiscoveryProposal>> allproposals,
            ILifecycleMappingRequirement requirement, IMavenDiscoveryProposal proposal) {

        List<IMavenDiscoveryProposal> proposals = allproposals.get(requirement);
        if (proposals == null) {
            proposals = new ArrayList<IMavenDiscoveryProposal>();
            allproposals.put(requirement, proposals);
        }

        if (!proposals.contains(proposal)) {
            proposals.add(proposal);
        }
    }

    public boolean implement(List<IMavenDiscoveryProposal> proposals, IRunnableWithProgress postInstallHook,
            IRunnableContext context, Collection<String> projectsToConfigure) {
        try {
            MavenDiscoveryInstallOperation runner = new MavenDiscoveryInstallOperation(toCatalogItems(proposals),
                    postInstallHook, true, false, projectsToConfigure);
            context.run(true, true, runner);
            int openInstallWizard = MavenDiscoveryUi.openInstallWizard(runner.getOperation(), true);
            return openInstallWizard == Window.OK;
        } catch (InvocationTargetException e) {
            IStatus status = new Status(IStatus.ERROR, DiscoveryActivator.PLUGIN_ID,
                    NLS.bind(Messages.ConnectorDiscoveryWizard_installProblems,
                            new Object[] { e.getCause().getMessage() }),
                    e.getCause());
            StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG);
            return false;
        } catch (InterruptedException e) {
            // canceled
            return false;
        }
    }

    private Collection<CatalogItem> toCatalogItems(List<IMavenDiscoveryProposal> proposals) {
        Set<CatalogItem> items = new HashSet<CatalogItem>();
        for (IMavenDiscoveryProposal proposal : proposals) {
            if (proposal instanceof InstallCatalogItemMavenDiscoveryProposal) {
                items.add(((InstallCatalogItemMavenDiscoveryProposal) proposal).getCatalogItem());
            }
        }
        return items;
    }

    public Object getService(Bundle bundle, ServiceRegistration registration) {
        return new MavenDiscoveryService(false); // not a factory instance
    }

    public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
    }
}