001    package 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    
022    import java.util.ArrayList;
023    import java.util.Collections;
024    import java.util.LinkedHashMap;
025    import java.util.List;
026    import java.util.Map;
027    
028    import org.apache.maven.model.Build;
029    import org.apache.maven.model.Dependency;
030    import org.apache.maven.model.Model;
031    import org.apache.maven.model.Plugin;
032    import org.apache.maven.model.building.ModelBuildingRequest;
033    import org.apache.maven.model.building.ModelProblemCollector;
034    import org.apache.maven.model.merge.MavenModelMerger;
035    import org.codehaus.plexus.component.annotations.Component;
036    import org.codehaus.plexus.util.StringUtils;
037    
038    /**
039     * Handles normalization of a model.
040     * 
041     * @author Benjamin Bentmann
042     */
043    @Component( role = ModelNormalizer.class )
044    public 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        private 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    }