View Javadoc
1   package org.apache.maven.model.transform;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.nio.file.Files;
23  import java.nio.file.Path;
24  import java.nio.file.Paths;
25  import java.util.List;
26  import java.util.Objects;
27  import java.util.Optional;
28  import java.util.function.Function;
29  
30  import org.apache.maven.model.transform.pull.NodeBufferingParser;
31  import org.codehaus.plexus.util.xml.pull.XmlPullParser;
32  
33  /**
34   * <p>
35   * Transforms relativePath to version.
36   * We could decide to simply allow {@code <parent/>}, but let's require the GA for now for checking
37   * This filter does NOT remove the relativePath (which is done by {@link RelativePathXMLFilter}, it will only
38   * optionally include the version based on the path
39   * </p>
40   *
41   * @author Robert Scholte
42   * @author Guillaume Nodet
43   * @since 4.0.0
44   */
45  class ParentXMLFilter
46      extends NodeBufferingParser
47  {
48  
49      private final Function<Path, Optional<RelativeProject>> relativePathMapper;
50  
51      private final Path projectPath;
52  
53      /**
54       * @param relativePathMapper
55       */
56      ParentXMLFilter( XmlPullParser parser,
57                       Function<Path, Optional<RelativeProject>> relativePathMapper, Path projectPath )
58      {
59          super( parser, "parent" );
60          this.relativePathMapper = relativePathMapper;
61          this.projectPath = projectPath;
62      }
63  
64      protected void process( List<Event> buffer )
65      {
66          String tagName = null;
67          String groupId = null;
68          String artifactId = null;
69          String version = null;
70          String relativePath = null;
71          String whitespaceAfterParentStart = "";
72          boolean hasVersion = false;
73          boolean hasRelativePath = false;
74          for ( int i = 0; i < buffer.size(); i++ )
75          {
76              Event event = buffer.get( i );
77              if ( event.event == START_TAG )
78              {
79                  tagName = event.name;
80                  hasVersion |= "version".equals( tagName );
81                  hasRelativePath |= "relativePath".equals( tagName );
82              }
83              else if ( event.event == TEXT )
84              {
85                  if ( event.text.matches( "\\s+" ) )
86                  {
87                      if ( whitespaceAfterParentStart.isEmpty() )
88                      {
89                          whitespaceAfterParentStart = event.text;
90                      }
91                  }
92                  else if ( "groupId".equals( tagName ) )
93                  {
94                      groupId = nullSafeAppend( groupId, event.text );
95                  }
96                  else if ( "artifactId".equals( tagName ) )
97                  {
98                      artifactId = nullSafeAppend( artifactId, event.text );
99                  }
100                 else if ( "relativePath".equals( tagName ) )
101                 {
102                     relativePath = nullSafeAppend( relativePath, event.text );
103                 }
104                 else if ( "version".equals( tagName ) )
105                 {
106                     version = nullSafeAppend( version, event.text );
107                 }
108             }
109             else if ( event.event == END_TAG && "parent".equals( event.name ) )
110             {
111                 Optional<RelativeProject> resolvedParent;
112                 if ( !hasVersion && ( !hasRelativePath || relativePath != null ) )
113                 {
114                     Path relPath = Paths.get( Objects.toString( relativePath, "../pom.xml" ) );
115                     resolvedParent = resolveRelativePath( relPath, groupId, artifactId );
116                 }
117                 else
118                 {
119                     resolvedParent = Optional.empty();
120                 }
121                 if ( !hasVersion && resolvedParent.isPresent() )
122                 {
123                     int pos = buffer.get( i - 1 ).event == TEXT ? i - 1  : i;
124                     Event e = new Event();
125                     e.event = TEXT;
126                     e.text = whitespaceAfterParentStart;
127                     buffer.add( pos++, e );
128                     e = new Event();
129                     e.event = START_TAG;
130                     e.namespace = buffer.get( 0 ).namespace;
131                     e.prefix = buffer.get( 0 ).prefix;
132                     e.name = "version";
133                     buffer.add( pos++, e );
134                     e = new Event();
135                     e.event = TEXT;
136                     e.text = resolvedParent.get().getVersion();
137                     buffer.add( pos++, e );
138                     e = new Event();
139                     e.event = END_TAG;
140                     e.name = "version";
141                     e.namespace = buffer.get( 0 ).namespace;
142                     e.prefix = buffer.get( 0 ).prefix;
143                     buffer.add( pos++, e );
144                 }
145                 break;
146             }
147         }
148         buffer.forEach( this::pushEvent );
149    }
150 
151 
152     protected Optional<RelativeProject> resolveRelativePath( Path relativePath, String groupId, String artifactId )
153     {
154         Path pomPath = projectPath.resolve( relativePath );
155         if ( Files.isDirectory( pomPath ) )
156         {
157             pomPath = pomPath.resolve( "pom.xml" );
158         }
159 
160         Optional<RelativeProject> mappedProject = relativePathMapper.apply( pomPath.normalize() );
161 
162         if ( mappedProject.isPresent() )
163         {
164             RelativeProject project = mappedProject.get();
165 
166             if ( Objects.equals( groupId, project.getGroupId() )
167                 && Objects.equals( artifactId, project.getArtifactId() ) )
168             {
169                 return mappedProject;
170             }
171         }
172         return Optional.empty();
173     }
174 
175 }