001    package org.apache.maven.model.plugin;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.util.ArrayList;
023    import java.util.Collection;
024    import java.util.Collections;
025    import java.util.Iterator;
026    import java.util.LinkedHashMap;
027    import java.util.List;
028    import java.util.Map;
029    
030    import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer;
031    import org.apache.maven.model.Build;
032    import org.apache.maven.model.Model;
033    import org.apache.maven.model.Plugin;
034    import org.apache.maven.model.PluginContainer;
035    import org.apache.maven.model.PluginExecution;
036    import org.apache.maven.model.PluginManagement;
037    import org.apache.maven.model.building.ModelBuildingRequest;
038    import org.apache.maven.model.building.ModelProblemCollector;
039    import org.apache.maven.model.building.ModelProblem.Severity;
040    import org.apache.maven.model.building.ModelProblem.Version;
041    import org.apache.maven.model.building.ModelProblemCollectorRequest;
042    import org.apache.maven.model.merge.MavenModelMerger;
043    import org.codehaus.plexus.component.annotations.Component;
044    import org.codehaus.plexus.component.annotations.Requirement;
045    
046    /**
047     * Handles injection of plugin executions induced by the lifecycle bindings for a packaging.
048     * 
049     * @author Benjamin Bentmann
050     */
051    @Component( role = LifecycleBindingsInjector.class )
052    public class DefaultLifecycleBindingsInjector
053        implements LifecycleBindingsInjector
054    {
055    
056        private LifecycleBindingsMerger merger = new LifecycleBindingsMerger();
057    
058        @Requirement
059        private LifeCyclePluginAnalyzer lifecycle;
060    
061        public void injectLifecycleBindings( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
062        {
063            String packaging = model.getPackaging();
064    
065            Collection<Plugin> defaultPlugins = lifecycle.getPluginsBoundByDefaultToAllLifecycles( packaging );
066    
067            if ( defaultPlugins == null )
068            {
069                problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
070                        .setMessage( "Unknown packaging: " + packaging )
071                        .setLocation( model.getLocation( "packaging" ) ) );
072            }
073            else if ( !defaultPlugins.isEmpty() )
074            {
075                Model lifecycleModel = new Model();
076                lifecycleModel.setBuild( new Build() );
077                lifecycleModel.getBuild().getPlugins().addAll( defaultPlugins );
078    
079                merger.merge( model, lifecycleModel );
080            }
081        }
082    
083        protected static class LifecycleBindingsMerger
084            extends MavenModelMerger
085        {
086    
087            private static final String PLUGIN_MANAGEMENT = "plugin-management";
088    
089            public void merge( Model target, Model source )
090            {
091                if ( target.getBuild() == null )
092                {
093                    target.setBuild( new Build() );
094                }
095    
096                Map<Object, Object> context =
097                    Collections.<Object, Object> singletonMap( PLUGIN_MANAGEMENT, target.getBuild().getPluginManagement() );
098    
099                mergePluginContainer_Plugins( target.getBuild(), source.getBuild(), false, context );
100            }
101    
102            @Override
103            protected void mergePluginContainer_Plugins( PluginContainer target, PluginContainer source,
104                                                         boolean sourceDominant, Map<Object, Object> context )
105            {
106                List<Plugin> src = source.getPlugins();
107                if ( !src.isEmpty() )
108                {
109                    List<Plugin> tgt = target.getPlugins();
110    
111                    Map<Object, Plugin> merged = new LinkedHashMap<Object, Plugin>( ( src.size() + tgt.size() ) * 2 );
112    
113                    for ( Plugin element : tgt )
114                    {
115                        Object key = getPluginKey( element );
116                        merged.put( key, element );
117                    }
118    
119                    Map<Object, Plugin> unmanaged = new LinkedHashMap<Object, Plugin>();
120    
121                    for ( Plugin element : src )
122                    {
123                        Object key = getPluginKey( element );
124                        Plugin existing = merged.get( key );
125                        if ( existing != null )
126                        {
127                            mergePlugin( existing, element, sourceDominant, context );
128                        }
129                        else
130                        {
131                            merged.put( key, element );
132                            unmanaged.put( key, element );
133                        }
134                    }
135    
136                    if ( !unmanaged.isEmpty() )
137                    {
138                        PluginManagement pluginMgmt = (PluginManagement) context.get( PLUGIN_MANAGEMENT );
139                        if ( pluginMgmt != null )
140                        {
141                            for ( Plugin managedPlugin : pluginMgmt.getPlugins() )
142                            {
143                                Object key = getPluginKey( managedPlugin );
144                                Plugin unmanagedPlugin = unmanaged.get( key );
145                                if ( unmanagedPlugin != null )
146                                {
147                                    Plugin plugin = managedPlugin.clone();
148                                    mergePlugin( plugin, unmanagedPlugin, sourceDominant, Collections.emptyMap() );
149                                    merged.put( key, plugin );
150                                }
151                            }
152                        }
153                    }
154    
155                    List<Plugin> result = new ArrayList<Plugin>( merged.values() );
156    
157                    target.setPlugins( result );
158                }
159            }
160    
161            @Override
162            protected void mergePluginExecution( PluginExecution target, PluginExecution source, boolean sourceDominant,
163                                                 Map<Object, Object> context )
164            {
165                super.mergePluginExecution( target, source, sourceDominant, context );
166    
167                target.setPriority( Math.min( target.getPriority(), source.getPriority() ) );
168            }
169    
170        }
171    
172    }