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        private 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 ( Iterator<Plugin> it = tgt.iterator(); it.hasNext(); )
114                    {
115                        Plugin element = it.next();
116                        Object key = getPluginKey( element );
117                        merged.put( key, element );
118                    }
119    
120                    Map<Object, Plugin> unmanaged = new LinkedHashMap<Object, Plugin>();
121    
122                    for ( Iterator<Plugin> it = src.iterator(); it.hasNext(); )
123                    {
124                        Plugin element = it.next();
125                        Object key = getPluginKey( element );
126                        Plugin existing = merged.get( key );
127                        if ( existing != null )
128                        {
129                            mergePlugin( existing, element, sourceDominant, context );
130                        }
131                        else
132                        {
133                            merged.put( key, element );
134                            unmanaged.put( key, element );
135                        }
136                    }
137    
138                    if ( !unmanaged.isEmpty() )
139                    {
140                        PluginManagement pluginMgmt = (PluginManagement) context.get( PLUGIN_MANAGEMENT );
141                        if ( pluginMgmt != null )
142                        {
143                            for ( Iterator<Plugin> it = pluginMgmt.getPlugins().iterator(); it.hasNext(); )
144                            {
145                                Plugin managedPlugin = it.next();
146                                Object key = getPluginKey( managedPlugin );
147                                Plugin unmanagedPlugin = unmanaged.get( key );
148                                if ( unmanagedPlugin != null )
149                                {
150                                    Plugin plugin = managedPlugin.clone();
151                                    mergePlugin( plugin, unmanagedPlugin, sourceDominant, Collections.emptyMap() );
152                                    merged.put( key, plugin );
153                                }
154                            }
155                        }
156                    }
157    
158                    List<Plugin> result = new ArrayList<Plugin>( merged.values() );
159    
160                    target.setPlugins( result );
161                }
162            }
163    
164            @Override
165            protected void mergePluginExecution( PluginExecution target, PluginExecution source, boolean sourceDominant,
166                                                 Map<Object, Object> context )
167            {
168                super.mergePluginExecution( target, source, sourceDominant, context );
169    
170                target.setPriority( Math.min( target.getPriority(), source.getPriority() ) );
171            }
172    
173        }
174    
175    }