org.eclipse.m2e.core.internal.lifecyclemapping.AnnotationMappingMetadataSource.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.m2e.core.internal.lifecyclemapping.AnnotationMappingMetadataSource.java

Source

/*******************************************************************************
 * Copyright (c) 2016 Anton Tanasenko.
 * 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:
 *      Anton Tanasenko - initial API and implementation
 *******************************************************************************/

package org.eclipse.m2e.core.internal.lifecyclemapping;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableMap;

import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.codehaus.plexus.util.xml.pull.MXParser;
import org.codehaus.plexus.util.xml.pull.XmlPullParser;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import org.apache.maven.model.InputLocation;
import org.apache.maven.model.InputLocationTracker;
import org.apache.maven.model.InputSource;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginContainer;
import org.apache.maven.model.PluginExecution;
import org.apache.maven.project.MavenProject;

import org.eclipse.m2e.core.internal.Messages;
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.PluginExecutionFilter;
import org.eclipse.m2e.core.internal.lifecyclemapping.model.PluginExecutionMetadata;
import org.eclipse.m2e.core.internal.markers.SourceLocation;
import org.eclipse.m2e.core.lifecyclemapping.model.PluginExecutionAction;
import org.eclipse.m2e.core.project.configurator.MojoExecutionKey;

/**
 * AnnotationMappingMetadataSource
 *
 * @author atgsl
 */
public class AnnotationMappingMetadataSource implements MappingMetadataSource {

    private static final String SELF = ""; //$NON-NLS-1$

    private final MavenProject project;

    private final String projectId;

    private final List<PI> pis;

    public static AnnotationMappingMetadataSource get(MavenProject project) {
        List<PI> pis = parsePIs(project);
        if (!pis.isEmpty()) {
            return new AnnotationMappingMetadataSource(project, pis);
        }
        return null;
    }

    private AnnotationMappingMetadataSource(MavenProject project, List<PI> pis) {
        this.project = project;
        this.pis = pis;
        projectId = project.getModel().getLocation(SELF).getSource().getModelId();
    }

    public List<PluginExecutionMetadata> getPluginExecutionMetadata(MojoExecutionKey execution) {
        Xpp3Dom action = getAction(execution);
        if (action != null) {
            return Collections.singletonList(createMetadata(action));
        }
        return Collections.emptyList();
    }

    private Xpp3Dom getAction(MojoExecutionKey execution) {

        String key = Plugin.constructKey(execution.getGroupId(), execution.getArtifactId());
        Plugin plugin = getPlugin(project.getBuild(), key);
        Plugin mplugin = getPlugin(project.getPluginManagement(), key);

        String executionId = execution.getExecutionId();
        if (executionId != null) {

            // find pi for the executionId
            if (plugin != null) {
                PluginExecution pluginExecution = plugin.getExecutionsAsMap().get(executionId);
                if (pluginExecution != null) {
                    Xpp3Dom action = getAction(pluginExecution);
                    if (action != null)
                        return action;
                }
            }
            if (mplugin != null) {
                PluginExecution pluginExecution = mplugin.getExecutionsAsMap().get(executionId);
                if (pluginExecution != null) {
                    Xpp3Dom action = getAction(pluginExecution);
                    if (action != null)
                        return action;
                }
            }

            // find pi for the whole plugin
            if (plugin != null) {
                Xpp3Dom action = getAction(plugin);
                if (action != null)
                    return action;
            }
            if (mplugin != null) {
                Xpp3Dom action = getAction(mplugin);
                if (action != null)
                    return action;
            }
        }
        return null;
    }

    private Plugin getPlugin(PluginContainer plugins, String key) {
        return plugins == null ? null : plugins.getPluginsAsMap().get(key);
    }

    public LifecycleMappingMetadata getLifecycleMappingMetadata(String packagingType)
            throws DuplicateMappingException {
        return null;
    }

    private Xpp3Dom getAction(InputLocationTracker tracker) {
        InputLocation location = tracker.getLocation(SELF);

        if (location != null && location.getSource() != null
                && projectId.equals(location.getSource().getModelId())) {
            int l = location.getLineNumber();
            int c = location.getColumnNumber();
            for (PI pi : pis) {
                if (pi.l == l && pi.c == c) {
                    return pi.action;
                }
            }
        }
        return null;
    }

    private PluginExecutionMetadata createMetadata(Xpp3Dom action) {
        Xpp3Dom actionDom = new Xpp3Dom("action"); //$NON-NLS-1$
        actionDom.addChild(action);

        PluginExecutionMetadata md = new PluginExecutionMetadata();
        md.setActionDom(actionDom);
        LifecycleMappingMetadataSource source = new LifecycleMappingMetadataSource();
        source.setSource(project);
        md.setSource(source);
        md.setFilter(new PluginExecutionFilter());
        return md;
    }

    private static List<PI> parsePIs(MavenProject project) {

        File pom = project.getFile();
        InputSource source = project.getModel().getLocation(SELF).getSource();

        List<PI> pis = new ArrayList<>();

        XmlPullParser parser = new MXParser();

        try (InputStream in = new FileInputStream(pom)) {
            parser.setInput(ReaderFactory.newXmlReader(in));

            Deque<State> stack = new LinkedList<>();

            int eventType = parser.getEventType();
            while (eventType != XmlPullParser.END_DOCUMENT) {

                if (eventType == XmlPullParser.START_TAG) {

                    stack.push(new State(parser.getLineNumber(), parser.getColumnNumber()));

                } else if (eventType == XmlPullParser.END_TAG) {

                    stack.pop();

                } else if (eventType == XmlPullParser.PROCESSING_INSTRUCTION && !stack.isEmpty()) {

                    String text = parser.getText();
                    if (text.startsWith("m2e ")) { //$NON-NLS-1$
                        // found it
                        Xpp3Dom dom = parse(text.substring(4));
                        if (dom == null) {
                            SourceLocation location = new SourceLocation(source.getLocation(), source.getModelId(),
                                    parser.getLineNumber(), parser.getColumnNumber(), text.length() + 4);
                            throw new LifecycleMappingConfigurationException(
                                    Messages.AnnotationMappingMetadataSource_UnsupportedInstructionFormat,
                                    location);
                        }
                        State s = stack.peek();
                        PI pi = new PI(s.l, s.c, dom);
                        pis.add(pi);
                    }
                }

                eventType = parser.nextToken();
            }

        } catch (XmlPullParserException | IOException ex) {
            SourceLocation location = new SourceLocation(source.getLocation(), source.getModelId(),
                    parser.getLineNumber(), parser.getColumnNumber(), 1);
            throw new LifecycleMappingConfigurationException(
                    Messages.AnnotationMappingMetadataSource_ErrorParsingInstruction, location);
        }

        return pis;
    }

    private static final Splitter PI_SPLITTER = Splitter.on(CharMatcher.WHITESPACE).omitEmptyStrings().limit(2);

    private static final Splitter EXECUTE_SPLITTER = Splitter.on(',').omitEmptyStrings();

    private static final Map<String, String> EXECUTE_OPTIONS = new ImmutableMap.Builder<String, String>()
            .put("onConfiguration", LifecycleMappingFactory.ELEMENT_RUN_ON_CONFIGURATION) //$NON-NLS-1$
            .put("onIncremental", LifecycleMappingFactory.ELEMENT_RUN_ON_INCREMENTAL).build(); //$NON-NLS-1$

    private static Xpp3Dom parse(String pi) {

        List<String> split = PI_SPLITTER.splitToList(pi);

        PluginExecutionAction a = getAction(split.get(0));
        if (a == null) {
            return null;
        }
        switch (a) {
        case ignore:
            return new Xpp3Dom("ignore"); //$NON-NLS-1$

        case configurator:
            if (split.size() != 2) {
                return null;
            }
            Xpp3Dom conf = new Xpp3Dom("configurator"); //$NON-NLS-1$
            Xpp3Dom id = new Xpp3Dom("id"); //$NON-NLS-1$
            id.setValue(split.get(1));
            conf.addChild(id);
            return conf;

        case execute:
            Xpp3Dom exec = new Xpp3Dom("execute"); //$NON-NLS-1$
            if (split.size() > 1) {
                for (String option : EXECUTE_SPLITTER.split(split.get(1))) {
                    String value = EXECUTE_OPTIONS.get(option);
                    if (value == null) {
                        return null;
                    }
                    Xpp3Dom opt = new Xpp3Dom(value);
                    opt.setValue("true"); //$NON-NLS-1$
                    exec.addChild(opt);
                }
            }
            return exec;

        default:
            return null;
        }
    }

    private static PluginExecutionAction getAction(String value) {
        for (PluginExecutionAction a : PluginExecutionAction.values()) {
            if (value.toLowerCase().equals(a.name())) {
                return a;
            }
        }
        return null;
    }

    private static class State {
        final int l;

        final int c;

        State(int l, int c) {
            this.l = l;
            this.c = c;
        }
    }

    private static class PI {
        final int l;

        final int c;

        final Xpp3Dom action;

        PI(int l, int c, Xpp3Dom action) {
            this.l = l;
            this.c = c;
            this.action = action;
        }
    }
}