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.codehaus.plexus.util.IOUtil;
28  import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
29  
30  /**
31   * BND Baseline check between two bundles.
32   *
33   * @goal baseline
34   * @phase verify
35   * @threadSafe true
36   * @since 2.4.1
37   */
38  public final class BaselinePlugin
39      extends AbstractBaselinePlugin
40  {
41  
42      private static final String TABLE_PATTERN = "%s %-50s %-10s %-10s %-10s %-10s %-10s";
43  
44      /**
45       * An XML output file to render to <code>${project.build.directory}/baseline.xml</code>.
46       *
47       * @parameter expression="${project.build.directory}/baseline.xml"
48       */
49      private File xmlOutputFile;
50  
51      /**
52       * Whether to log the results to the console or not, true by default.
53       *
54       * @parameter expression="${logResults}" default-value="true"
55       */
56      private boolean logResults;
57  
58      private FileWriter xmlFileWriter;
59  
60      private PrettyPrintXMLWriter xmlWriter;
61  
62      protected void init()
63      {
64          if ( xmlOutputFile != null )
65          {
66              xmlOutputFile.getParentFile().mkdirs();
67              try
68              {
69                  xmlFileWriter = new FileWriter( xmlOutputFile );
70                  xmlWriter = new PrettyPrintXMLWriter( xmlFileWriter );
71              }
72              catch ( IOException e )
73              {
74                  getLog().warn( "No XML report will be produced, cannot write data to " + xmlOutputFile, e );
75              }
76          }
77      }
78  
79      protected void startBaseline( String generationDate,
80                                    String bundleName,
81                                    String currentVersion,
82                                    String previousVersion )
83      {
84          if ( isLoggingResults() )
85          {
86              log( "Baseline Report - Generated by Apache Felix Maven Bundle Plugin on %s based on Bnd - see http://www.aqute.biz/Bnd/Bnd",
87                   generationDate );
88              log( "Comparing bundle %s version %s to version %s", bundleName, currentVersion, previousVersion );
89              log( "" );
90              log( TABLE_PATTERN,
91                   " ",
92                   "PACKAGE_NAME",
93                   "DELTA",
94                   "CUR_VER",
95                   "BASE_VER",
96                   "REC_VER",
97                   "WARNINGS",
98                   "ATTRIBUTES" );
99              log( TABLE_PATTERN,
100                  "=",
101                  "==================================================",
102                  "==========",
103                  "==========",
104                  "==========",
105                  "==========",
106                  "==========",
107                  "==========" );
108         }
109 
110         if ( isProducingXml() )
111         {
112             xmlWriter.startElement( "baseline" );
113             xmlWriter.addAttribute( "version", "1.0.0" );
114             xmlWriter.addAttribute( "vendor", "The Apache Software Foundation" );
115             xmlWriter.addAttribute( "vendorURL", "http://www.apache.org/" );
116             xmlWriter.addAttribute( "generator", "Apache Felix Maven Bundle Plugin" );
117             xmlWriter.addAttribute( "generatorURL", "http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html" );
118             xmlWriter.addAttribute( "analyzer", "Bnd" );
119             xmlWriter.addAttribute( "analyzerURL", "http://www.aqute.biz/Bnd/Bnd" );
120             xmlWriter.addAttribute( "generatedOn", generationDate );
121             xmlWriter.addAttribute( "bundleName", bundleName );
122             xmlWriter.addAttribute( "currentVersion", currentVersion );
123             xmlWriter.addAttribute( "previousVersion", previousVersion );
124         }
125     }
126 
127     protected void startPackage( boolean mismatch,
128                                  String name,
129                                  String shortDelta,
130                                  String delta,
131                                  String newerVersion,
132                                  String olderVersion,
133                                  String suggestedVersion,
134                                  DiffMessage diffMessage,
135                                  Map<String,String> attributes )
136     {
137         if ( isLoggingResults() )
138         {
139             log( TABLE_PATTERN,
140                  mismatch ? '*' : shortDelta,
141                  name,
142                  delta,
143                  newerVersion,
144                  olderVersion,
145                  suggestedVersion,
146                  diffMessage != null ? diffMessage : '-',
147                  attributes );
148         }
149 
150         if ( isProducingXml() )
151         {
152             xmlWriter.startElement( "package" );
153             xmlWriter.addAttribute( "name", name );
154             xmlWriter.addAttribute( "delta", delta );
155             simpleElement( "mismatch", String.valueOf( mismatch ) );
156             simpleElement( "newerVersion", newerVersion );
157             simpleElement( "olderVersion", olderVersion );
158             simpleElement( "suggestedVersion", suggestedVersion );
159 
160             if ( diffMessage != null )
161             {
162                 simpleElement( diffMessage.getType().name(), diffMessage.getMessage() );
163             }
164 
165             xmlWriter.startElement( "attributes" );
166             if (attributes != null)
167             {
168                 for (Entry<String, String> attribute : attributes.entrySet())
169                 {
170                     String attributeName = attribute.getKey();
171                     if (':' == attributeName.charAt(attributeName.length() - 1))
172                     {
173                         attributeName = attributeName.substring(0, attributeName.length() - 1);
174                     }
175                     String attributeValue = attribute.getValue();
176 
177                     xmlWriter.startElement(attributeName);
178                     xmlWriter.writeText(attributeValue);
179                     xmlWriter.endElement();
180                 }
181             }
182             xmlWriter.endElement();
183         }
184     }
185 
186     protected void startDiff( int depth, String type, String name, String delta, String shortDelta )
187     {
188         if ( isLoggingResults() )
189         {
190             log( "%-" + (depth * 4) + "s %s %s %s",
191                  "",
192                  shortDelta,
193                  type,
194                  name );
195         }
196 
197         if ( isProducingXml() )
198         {
199             xmlWriter.startElement( type );
200             xmlWriter.addAttribute( "name", name );
201             xmlWriter.addAttribute( "delta", delta );
202         }
203     }
204 
205     protected void endDiff( int depth )
206     {
207         if ( isProducingXml() )
208         {
209             xmlWriter.endElement();
210         }
211     }
212 
213     protected void endPackage()
214     {
215         if ( isLoggingResults() )
216         {
217             log( "-----------------------------------------------------------------------------------------------------------" );
218         }
219 
220         if ( isProducingXml() )
221         {
222             xmlWriter.endElement();
223         }
224     }
225 
226     protected void endBaseline()
227     {
228         if ( xmlWriter != null )
229         {
230             xmlWriter.endElement();
231             IOUtil.close( xmlFileWriter );
232         }
233     }
234 
235     private boolean isProducingXml()
236     {
237         return xmlFileWriter!= null && xmlWriter != null;
238     }
239 
240     private boolean isLoggingResults()
241     {
242         return logResults && getLog().isInfoEnabled();
243     }
244 
245     private void log( String format, Object...args )
246     {
247         getLog().info( String.format( format, args ) );
248     }
249 
250     private void simpleElement( String name, String value )
251     {
252         xmlWriter.startElement( name );
253         xmlWriter.writeText( value );
254         xmlWriter.endElement();
255     }
256 
257 }