001package org.apache.maven.project;
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
022import java.util.ArrayList;
023import java.util.Iterator;
024import java.util.LinkedHashMap;
025import java.util.List;
026import java.util.Map;
027import java.util.TreeMap;
028
029import org.apache.maven.model.Dependency;
030import org.apache.maven.model.Plugin;
031import org.apache.maven.model.PluginContainer;
032import org.apache.maven.model.PluginExecution;
033import org.apache.maven.model.Repository;
034import org.codehaus.plexus.util.xml.Xpp3Dom;
035
036/** @deprecated */
037@Deprecated
038public final class ModelUtils
039{
040
041    /**
042     * This should be the resulting ordering of plugins after merging:
043     * <p/>
044     * Given:
045     * <p/>
046     * parent: X -> A -> B -> D -> E
047     * child: Y -> A -> C -> D -> F
048     * <p/>
049     * Result:
050     * <p/>
051     * X -> Y -> A -> B -> C -> D -> E -> F
052     */
053    public static void mergePluginLists( PluginContainer childContainer, PluginContainer parentContainer,
054                                         boolean handleAsInheritance )
055    {
056        if ( ( childContainer == null ) || ( parentContainer == null ) )
057        {
058            // nothing to do.
059            return;
060        }
061
062        List<Plugin> parentPlugins = parentContainer.getPlugins();
063
064        if ( ( parentPlugins != null ) && !parentPlugins.isEmpty() )
065        {
066            parentPlugins = new ArrayList<>( parentPlugins );
067
068            // If we're processing this merge as an inheritance, we have to build up a list of
069            // plugins that were considered for inheritance.
070            if ( handleAsInheritance )
071            {
072                for ( Iterator<Plugin> it = parentPlugins.iterator(); it.hasNext(); )
073                {
074                    Plugin plugin = it.next();
075
076                    String inherited = plugin.getInherited();
077
078                    if ( ( inherited != null ) && !Boolean.valueOf( inherited ) )
079                    {
080                        it.remove();
081                    }
082                }
083            }
084
085            List<Plugin> assembledPlugins = new ArrayList<>();
086
087            Map<String, Plugin> childPlugins = childContainer.getPluginsAsMap();
088
089            for ( Plugin parentPlugin : parentPlugins )
090            {
091                String parentInherited = parentPlugin.getInherited();
092
093                // only merge plugin definition from the parent if at least one
094                // of these is true:
095                // 1. we're not processing the plugins in an inheritance-based merge
096                // 2. the parent's <inherited/> flag is not set
097                // 3. the parent's <inherited/> flag is set to true
098                if ( !handleAsInheritance || ( parentInherited == null )
099                    || Boolean.valueOf( parentInherited ) )
100                {
101                    Plugin childPlugin = childPlugins.get( parentPlugin.getKey() );
102
103                    if ( ( childPlugin != null ) && !assembledPlugins.contains( childPlugin ) )
104                    {
105                        Plugin assembledPlugin = childPlugin;
106
107                        mergePluginDefinitions( childPlugin, parentPlugin, handleAsInheritance );
108
109                        // fix for MNG-2221 (assembly cache was not being populated for later reference):
110                        assembledPlugins.add( assembledPlugin );
111                    }
112
113                    // if we're processing this as an inheritance-based merge, and
114                    // the parent's <inherited/> flag is not set, then we need to
115                    // clear the inherited flag in the merge result.
116                    if ( handleAsInheritance && ( parentInherited == null ) )
117                    {
118                        parentPlugin.unsetInheritanceApplied();
119                    }
120                }
121
122                // very important to use the parentPlugins List, rather than parentContainer.getPlugins()
123                // since this list is a local one, and may have been modified during processing.
124                List<Plugin> results =
125                    ModelUtils.orderAfterMerge( assembledPlugins, parentPlugins, childContainer.getPlugins() );
126
127                childContainer.setPlugins( results );
128
129                childContainer.flushPluginMap();
130            }
131        }
132    }
133
134    public static List<Plugin> orderAfterMerge( List<Plugin> merged, List<Plugin> highPrioritySource,
135                                                List<Plugin> lowPrioritySource )
136    {
137        List<Plugin> results = new ArrayList<>();
138
139        if ( !merged.isEmpty() )
140        {
141            results.addAll( merged );
142        }
143
144        List<Plugin> missingFromResults = new ArrayList<>();
145
146        List<List<Plugin>> sources = new ArrayList<>();
147
148        sources.add( highPrioritySource );
149        sources.add( lowPrioritySource );
150
151        for ( List<Plugin> source : sources )
152        {
153            for ( Plugin item : source )
154            {
155                if ( results.contains( item ) )
156                {
157                    if ( !missingFromResults.isEmpty() )
158                    {
159                        int idx = results.indexOf( item );
160
161                        if ( idx < 0 )
162                        {
163                            idx = 0;
164                        }
165
166                        results.addAll( idx, missingFromResults );
167
168                        missingFromResults.clear();
169                    }
170                }
171                else
172                {
173                    missingFromResults.add( item );
174                }
175            }
176
177            if ( !missingFromResults.isEmpty() )
178            {
179                results.addAll( missingFromResults );
180
181                missingFromResults.clear();
182            }
183        }
184
185        return results;
186    }
187
188
189    public static void mergePluginDefinitions( Plugin child, Plugin parent, boolean handleAsInheritance )
190    {
191        if ( ( child == null ) || ( parent == null ) )
192        {
193            // nothing to do.
194            return;
195        }
196
197        if ( parent.isExtensions() )
198        {
199            child.setExtensions( true );
200        }
201
202        if ( ( child.getVersion() == null ) && ( parent.getVersion() != null ) )
203        {
204            child.setVersion( parent.getVersion() );
205        }
206
207        Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
208        Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
209
210        childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
211
212        child.setConfiguration( childConfiguration );
213
214        child.setDependencies( mergeDependencyList( child.getDependencies(), parent.getDependencies() ) );
215
216        // from here to the end of the method is dealing with merging of the <executions/> section.
217        String parentInherited = parent.getInherited();
218
219        boolean parentIsInherited = ( parentInherited == null ) || Boolean.valueOf( parentInherited );
220
221        List<PluginExecution> parentExecutions = parent.getExecutions();
222
223        if ( ( parentExecutions != null ) && !parentExecutions.isEmpty() )
224        {
225            List<PluginExecution> mergedExecutions = new ArrayList<>();
226
227            Map<String, PluginExecution> assembledExecutions = new TreeMap<>();
228
229            Map<String, PluginExecution> childExecutions = child.getExecutionsAsMap();
230
231            for ( PluginExecution parentExecution : parentExecutions )
232            {
233                String inherited = parentExecution.getInherited();
234
235                boolean parentExecInherited =
236                    parentIsInherited && ( ( inherited == null ) || Boolean.valueOf( inherited ) );
237
238                if ( !handleAsInheritance || parentExecInherited )
239                {
240                    PluginExecution assembled = parentExecution;
241
242                    PluginExecution childExecution = childExecutions.get( parentExecution.getId() );
243
244                    if ( childExecution != null )
245                    {
246                        mergePluginExecutionDefinitions( childExecution, parentExecution );
247
248                        assembled = childExecution;
249                    }
250                    else if ( handleAsInheritance && ( parentInherited == null ) )
251                    {
252                        parentExecution.unsetInheritanceApplied();
253                    }
254
255                    assembledExecutions.put( assembled.getId(), assembled );
256                    mergedExecutions.add( assembled );
257                }
258            }
259
260            for ( PluginExecution childExecution : child.getExecutions() )
261            {
262                if ( !assembledExecutions.containsKey( childExecution.getId() ) )
263                {
264                    mergedExecutions.add( childExecution );
265                }
266            }
267
268            child.setExecutions( mergedExecutions );
269
270            child.flushExecutionMap();
271        }
272
273    }
274
275    private static void mergePluginExecutionDefinitions( PluginExecution child, PluginExecution parent )
276    {
277        if ( child.getPhase() == null )
278        {
279            child.setPhase( parent.getPhase() );
280        }
281
282        List<String> parentGoals = parent.getGoals();
283        List<String> childGoals = child.getGoals();
284
285        List<String> goals = new ArrayList<>();
286
287        if ( ( childGoals != null ) && !childGoals.isEmpty() )
288        {
289            goals.addAll( childGoals );
290        }
291
292        if ( parentGoals != null )
293        {
294            for (  String goal : parentGoals )
295            {
296                if ( !goals.contains( goal ) )
297                {
298                    goals.add( goal );
299                }
300            }
301        }
302
303        child.setGoals( goals );
304
305        Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
306        Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
307
308        childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
309
310        child.setConfiguration( childConfiguration );
311    }
312
313    public static List<Repository> mergeRepositoryLists( List<Repository> dominant, List<Repository> recessive )
314    {
315        List<Repository> repositories = new ArrayList<>();
316
317        for ( Repository repository : dominant )
318        {
319            repositories.add( repository );
320        }
321
322        for ( Repository repository : recessive )
323        {
324            if ( !repositories.contains( repository ) )
325            {
326                repositories.add( repository );
327            }
328        }
329
330        return repositories;
331    }
332
333    public static void mergeFilterLists( List<String> childFilters, List<String> parentFilters )
334    {
335        for ( String f : parentFilters )
336        {
337            if ( !childFilters.contains( f ) )
338            {
339                childFilters.add( f );
340            }
341        }
342    }
343
344    private static List<Dependency> mergeDependencyList( List<Dependency> child, List<Dependency> parent )
345    {
346        Map<String, Dependency> depsMap = new LinkedHashMap<>();
347
348        if ( parent != null )
349        {
350            for ( Dependency dependency : parent )
351            {
352                depsMap.put( dependency.getManagementKey(), dependency );
353            }
354        }
355
356        if ( child != null )
357        {
358            for ( Dependency dependency : child )
359            {
360                depsMap.put( dependency.getManagementKey(), dependency );
361            }
362        }
363
364        return new ArrayList<>( depsMap.values() );
365    }
366
367}