001package org.apache.maven.model.normalization;
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.Collections;
024import java.util.LinkedHashMap;
025import java.util.List;
026import java.util.Map;
027
028import org.apache.maven.model.Build;
029import org.apache.maven.model.Dependency;
030import org.apache.maven.model.Model;
031import org.apache.maven.model.Plugin;
032import org.apache.maven.model.building.ModelBuildingRequest;
033import org.apache.maven.model.building.ModelProblemCollector;
034import org.apache.maven.model.merge.MavenModelMerger;
035import org.codehaus.plexus.component.annotations.Component;
036import org.codehaus.plexus.util.StringUtils;
037
038/**
039 * Handles normalization of a model.
040 * 
041 * @author Benjamin Bentmann
042 */
043@Component( role = ModelNormalizer.class )
044public class DefaultModelNormalizer
045    implements ModelNormalizer
046{
047
048    private DuplicateMerger merger = new DuplicateMerger();
049
050    public void mergeDuplicates( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
051    {
052        Build build = model.getBuild();
053        if ( build != null )
054        {
055            List<Plugin> plugins = build.getPlugins();
056            Map<Object, Plugin> normalized = new LinkedHashMap<Object, Plugin>( plugins.size() * 2 );
057
058            for ( Plugin plugin : plugins )
059            {
060                Object key = plugin.getKey();
061                Plugin first = normalized.get( key );
062                if ( first != null )
063                {
064                    merger.mergePlugin( plugin, first );
065                }
066                normalized.put( key, plugin );
067            }
068
069            if ( plugins.size() != normalized.size() )
070            {
071                build.setPlugins( new ArrayList<Plugin>( normalized.values() ) );
072            }
073        }
074
075        /*
076         * NOTE: This is primarily to keep backward-compat with Maven 2.x which did not validate that dependencies are
077         * unique within a single POM. Upon multiple declarations, 2.x just kept the last one but retained the order of
078         * the first occurrence. So when we're in lenient/compat mode, we have to deal with such broken POMs and mimic
079         * the way 2.x works. When we're in strict mode, the removal of duplicates just saves other merging steps from
080         * aftereffects and bogus error messages.
081         */
082        List<Dependency> dependencies = model.getDependencies();
083        Map<String, Dependency> normalized = new LinkedHashMap<String, Dependency>( dependencies.size() * 2 );
084
085        for ( Dependency dependency : dependencies )
086        {
087            normalized.put( dependency.getManagementKey(), dependency );
088        }
089
090        if ( dependencies.size() != normalized.size() )
091        {
092            model.setDependencies( new ArrayList<Dependency>( normalized.values() ) );
093        }
094    }
095
096    protected static class DuplicateMerger
097        extends MavenModelMerger
098    {
099
100        public void mergePlugin( Plugin target, Plugin source )
101        {
102            super.mergePlugin( target, source, false, Collections.emptyMap() );
103        }
104
105    }
106
107    public void injectDefaultValues( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
108    {
109        injectDependencyDefaults( model.getDependencies() );
110
111        Build build = model.getBuild();
112        if ( build != null )
113        {
114            for ( Plugin plugin : build.getPlugins() )
115            {
116                injectDependencyDefaults( plugin.getDependencies() );
117            }
118        }
119    }
120
121    private void injectDependencyDefaults( List<Dependency> dependencies )
122    {
123        for ( Dependency dependency : dependencies )
124        {
125            if ( StringUtils.isEmpty( dependency.getScope() ) )
126            {
127                // we cannot set this directly in the MDO due to the interactions with dependency management
128                dependency.setScope( "compile" );
129            }
130        }
131    }
132
133}