View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.felix.bundleplugin.baseline;
20  
21  import java.io.File;
22  import java.io.FileWriter;
23  import java.io.IOException;
24  import java.util.Map;
25  import java.util.Map.Entry;
26  
27  import org.apache.maven.plugins.annotations.LifecyclePhase;
28  import org.apache.maven.plugins.annotations.Mojo;
29  import org.apache.maven.plugins.annotations.Parameter;
30  import org.apache.maven.plugins.annotations.ResolutionScope;
31  import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
32  import org.codehaus.plexus.util.xml.XMLWriter;
33  
34  import aQute.bnd.version.Version;
35  
36  /**
37   * BND Baseline check between two bundles.
38   * @since 2.4.1
39   */
40  @Mojo( name = "baseline", threadSafe = true,
41         requiresDependencyResolution = ResolutionScope.TEST,
42         defaultPhase = LifecyclePhase.VERIFY)
43  public final class BaselinePlugin
44      extends AbstractBaselinePlugin
45  {
46  
47      private static final String TABLE_PATTERN = "%s %-50s %-10s %-10s %-10s %-10s %-10s";
48  
49      /**
50       * An XML output file to render to <code>${project.build.directory}/baseline.xml</code>.
51       */
52      @Parameter(defaultValue="${project.build.directory}/baseline.xml")
53      private File xmlOutputFile;
54  
55      /**
56       * Whether to log the results to the console or not, true by default.
57       */
58      @Parameter(defaultValue="true", property="logResults" )
59      private boolean logResults;
60  
61      private static final class Context {
62          public FileWriter writer;
63          public XMLWriter xmlWriter;
64      }
65  
66      @Override
67      protected Object init(final Object noContext)
68      {
69          if ( xmlOutputFile != null )
70          {
71              xmlOutputFile.getParentFile().mkdirs();
72              try
73              {
74                  final Context ctx = new Context();
75                  ctx.writer = new FileWriter( xmlOutputFile );
76                  ctx.xmlWriter = new PrettyPrintXMLWriter( ctx.writer );
77                  return ctx;
78              }
79              catch ( IOException e )
80              {
81                  getLog().warn( "No XML report will be produced, cannot write data to " + xmlOutputFile, e );
82              }
83          }
84          return null;
85      }
86  
87      @Override
88      protected void close(final Object writer)
89      {
90          if ( writer != null )
91          {
92              try {
93  
94                  ((Context)writer).writer.close();
95              }
96              catch (IOException e)
97              {
98                  // ignore
99              }
100         }
101     }
102     @Override
103     protected void startBaseline( Object context,
104                                   String generationDate,
105                                   String bundleName,
106                                   String currentVersion,
107                                   String previousVersion )
108     {
109         final XMLWriter xmlWriter = context == null ? null : ((Context)context).xmlWriter;
110         if ( isLoggingResults() )
111         {
112             log( "Baseline Report - Generated by Apache Felix Maven Bundle Plugin on %s based on Bnd - see http://www.aqute.biz/Bnd/Bnd",
113                  generationDate );
114             log( "Comparing bundle %s version %s to version %s", bundleName, currentVersion, previousVersion );
115             log( "" );
116             log( TABLE_PATTERN,
117                  " ",
118                  "PACKAGE_NAME",
119                  "DELTA",
120                  "CUR_VER",
121                  "BASE_VER",
122                  "REC_VER",
123                  "WARNINGS",
124                  "ATTRIBUTES" );
125             log( TABLE_PATTERN,
126                  "=",
127                  "==================================================",
128                  "==========",
129                  "==========",
130                  "==========",
131                  "==========",
132                  "==========",
133                  "==========" );
134         }
135 
136         if ( xmlWriter != null )
137         {
138             xmlWriter.startElement( "baseline" );
139             xmlWriter.addAttribute( "version", "1.0.0" );
140             xmlWriter.addAttribute( "vendor", "The Apache Software Foundation" );
141             xmlWriter.addAttribute( "vendorURL", "http://www.apache.org/" );
142             xmlWriter.addAttribute( "generator", "Apache Felix Maven Bundle Plugin" );
143             xmlWriter.addAttribute( "generatorURL", "http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html" );
144             xmlWriter.addAttribute( "analyzer", "Bnd" );
145             xmlWriter.addAttribute( "analyzerURL", "http://www.aqute.biz/Bnd/Bnd" );
146             xmlWriter.addAttribute( "generatedOn", generationDate );
147             xmlWriter.addAttribute( "bundleName", bundleName );
148             xmlWriter.addAttribute( "currentVersion", currentVersion );
149             xmlWriter.addAttribute( "previousVersion", previousVersion );
150         }
151     }
152 
153     @Override
154     protected void startPackage( Object context,
155                                  boolean mismatch,
156                                  String name,
157                                  String shortDelta,
158                                  String delta,
159                                  Version newerVersion,
160                                  Version olderVersion,
161                                  Version suggestedVersion,
162                                  DiffMessage diffMessage,
163                                  Map<String,String> attributes )
164     {
165         final XMLWriter xmlWriter = context == null ? null : ((Context)context).xmlWriter;
166         if ( isLoggingResults() )
167         {
168             log( TABLE_PATTERN,
169                  mismatch ? '*' : shortDelta,
170                  name,
171                  delta,
172                  newerVersion,
173                  olderVersion,
174                  suggestedVersion,
175                  diffMessage != null ? diffMessage : '-',
176                  attributes );
177         }
178 
179         if ( xmlWriter != null )
180         {
181             xmlWriter.startElement( "package" );
182             xmlWriter.addAttribute( "name", name );
183             xmlWriter.addAttribute( "delta", delta );
184             simpleElement( xmlWriter, "mismatch", String.valueOf( mismatch ) );
185             simpleElement( xmlWriter, "newerVersion", newerVersion.toString() );
186             simpleElement( xmlWriter, "olderVersion", olderVersion.toString() );
187             if ( suggestedVersion != null )
188             {
189                 simpleElement( xmlWriter, "suggestedVersion", suggestedVersion.toString() );
190             }
191 
192             if ( diffMessage != null )
193             {
194                 simpleElement( xmlWriter, diffMessage.getType().name(), diffMessage.getMessage() );
195             }
196 
197             xmlWriter.startElement( "attributes" );
198             if (attributes != null)
199             {
200                 for (Entry<String, String> attribute : attributes.entrySet())
201                 {
202                     String attributeName = attribute.getKey();
203                     if (':' == attributeName.charAt(attributeName.length() - 1))
204                     {
205                         attributeName = attributeName.substring(0, attributeName.length() - 1);
206                     }
207                     String attributeValue = attribute.getValue();
208 
209                     xmlWriter.startElement(attributeName);
210                     xmlWriter.writeText(attributeValue);
211                     xmlWriter.endElement();
212                 }
213             }
214             xmlWriter.endElement();
215         }
216     }
217 
218     @Override
219     protected void startDiff( Object context, int depth, String type, String name, String delta, String shortDelta )
220     {
221         final XMLWriter xmlWriter = context == null ? null : ((Context)context).xmlWriter;
222         if ( isLoggingResults() )
223         {
224             log( "%-" + (depth * 4) + "s %s %s %s",
225                  "",
226                  shortDelta,
227                  type,
228                  name );
229         }
230 
231         if ( xmlWriter != null )
232         {
233             xmlWriter.startElement( type );
234             xmlWriter.addAttribute( "name", name );
235             xmlWriter.addAttribute( "delta", delta );
236         }
237     }
238 
239     @Override
240     protected void endDiff( Object context, int depth )
241     {
242         final XMLWriter xmlWriter = context == null ? null : ((Context)context).xmlWriter;
243         if ( xmlWriter != null )
244         {
245             xmlWriter.endElement();
246         }
247     }
248 
249     @Override
250     protected void endPackage(Object context)
251     {
252         final XMLWriter xmlWriter = context == null ? null : ((Context)context).xmlWriter;
253         if ( isLoggingResults() )
254         {
255             log( "-----------------------------------------------------------------------------------------------------------" );
256         }
257 
258         if ( xmlWriter != null )
259         {
260             xmlWriter.endElement();
261         }
262     }
263 
264     @Override
265     protected void endBaseline(Object context)
266     {
267         final XMLWriter xmlWriter = context == null ? null : ((Context)context).xmlWriter;
268         if ( xmlWriter != null )
269         {
270             xmlWriter.endElement();
271         }
272     }
273 
274     private boolean isLoggingResults()
275     {
276         return logResults && getLog().isInfoEnabled();
277     }
278 
279     private void log( String format, Object...args )
280     {
281         getLog().info( String.format( format, args ) );
282     }
283 
284     private void simpleElement( XMLWriter xmlWriter, String name, String value )
285     {
286         xmlWriter.startElement( name );
287         xmlWriter.writeText( value );
288         xmlWriter.endElement();
289     }
290 }