View Javadoc
1   package org.apache.maven.plugin.jira;
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.io.File;
23  import java.io.FileInputStream;
24  import java.io.FileNotFoundException;
25  import java.io.InputStream;
26  import java.text.ParseException;
27  import java.text.SimpleDateFormat;
28  import java.util.ArrayList;
29  import java.util.Collections;
30  import java.util.List;
31  import java.util.Locale;
32  
33  import javax.xml.parsers.SAXParser;
34  import javax.xml.parsers.SAXParserFactory;
35  
36  import org.apache.maven.plugin.MojoExecutionException;
37  import org.apache.maven.plugin.issues.Issue;
38  import org.apache.maven.plugin.logging.Log;
39  import org.codehaus.plexus.util.IOUtil;
40  import org.xml.sax.Attributes;
41  import org.xml.sax.InputSource;
42  import org.xml.sax.SAXException;
43  import org.xml.sax.helpers.DefaultHandler;
44  
45  /**
46   * XML parser that extracts <code>Issue</code>s from JIRA. This works on an XML file downloaded from JIRA and creates a
47   * <code>List</code> of issues that is exposed to the user of the class.
48   * 
49   * @version $Id: JiraXML.java 1384337 2012-09-13 13:53:19Z olamy $
50   */
51  public class JiraXML
52      extends DefaultHandler
53  {
54      private final List<Issue> issueList;
55  
56      private final StringBuilder currentElement = new StringBuilder( 1024 );
57  
58      private String currentParent = "";
59  
60      private final String datePattern;
61  
62      private Issue issue;
63  
64      private String jiraVersion = null;
65  
66      private final Log log;
67  
68      private SimpleDateFormat sdf = null;
69  
70      /**
71       * @param log not null.
72       * @param datePattern may be null.
73       * @since 2.4
74       */
75      public JiraXML( Log log, String datePattern )
76      {
77          this.log = log;
78          this.datePattern = datePattern;
79  
80          if ( datePattern == null )
81          {
82              sdf = null;
83          }
84          else
85          {
86              // @todo Do we need to be able to configure the locale of the JIRA server as well?
87              sdf = new SimpleDateFormat( datePattern, Locale.ENGLISH );
88          }
89  
90          this.issueList = new ArrayList<Issue>( 16 );
91      }
92  
93      /**
94       * Parse the given xml file. The list of issues can then be retrieved with {@link #getIssueList()}.
95       * 
96       * @param xmlPath the file to pares.
97       * @throws MojoExecutionException
98       * @since 2.4
99       */
100     public void parseXML( File xmlPath )
101         throws MojoExecutionException
102     {
103         InputStream xmlStream = null;
104         try
105         {
106             xmlStream = new FileInputStream( xmlPath );
107             InputSource inputSource = new InputSource( xmlStream );
108             parse( inputSource );
109         }
110         catch ( FileNotFoundException e )
111         {
112             throw new MojoExecutionException( "Failed to open JIRA XML file " + xmlPath, e );
113         }
114         finally
115         {
116             IOUtil.close( xmlStream );
117         }
118     }
119 
120     void parse( InputSource xmlSource )
121         throws MojoExecutionException
122     {
123         try
124         {
125             SAXParserFactory factory = SAXParserFactory.newInstance();
126             SAXParser saxParser = factory.newSAXParser();
127 
128             saxParser.parse( xmlSource, this );
129         }
130         catch ( Throwable t )
131         {
132             throw new MojoExecutionException( "Failed to parse JIRA XML.", t );
133         }
134     }
135 
136     public void startElement( String namespaceURI, String sName, String qName, Attributes attrs )
137         throws SAXException
138     {
139         if ( qName.equals( "item" ) )
140         {
141             issue = new Issue();
142 
143             currentParent = "item";
144         }
145         else if ( qName.equals( "key" ) )
146         {
147             String id = attrs.getValue( "id" );
148             if ( id != null )
149             {
150                 issue.setId( id.trim() );
151             }
152         }
153         else if ( qName.equals( "build-info" ) )
154         {
155             currentParent = "build-info";
156         }
157     }
158 
159     public void endElement( String namespaceURI, String sName, String qName )
160         throws SAXException
161     {
162         if ( qName.equals( "item" ) )
163         {
164             issueList.add( issue );
165 
166             currentParent = "";
167         }
168         else if ( qName.equals( "key" ) )
169         {
170             issue.setKey( currentElement.toString().trim() );
171         }
172         else if ( qName.equals( "summary" ) )
173         {
174             issue.setSummary( currentElement.toString().trim() );
175         }
176         else if ( qName.equals( "type" ) )
177         {
178             issue.setType( currentElement.toString().trim() );
179         }
180         else if ( qName.equals( "link" ) && currentParent.equals( "item" ) )
181         {
182             issue.setLink( currentElement.toString().trim() );
183         }
184         else if ( qName.equals( "priority" ) )
185         {
186             issue.setPriority( currentElement.toString().trim() );
187         }
188         else if ( qName.equals( "status" ) )
189         {
190             issue.setStatus( currentElement.toString().trim() );
191         }
192         else if ( qName.equals( "resolution" ) )
193         {
194             issue.setResolution( currentElement.toString().trim() );
195         }
196         else if ( qName.equals( "assignee" ) )
197         {
198             issue.setAssignee( currentElement.toString().trim() );
199         }
200         else if ( qName.equals( "reporter" ) )
201         {
202             issue.setReporter( currentElement.toString().trim() );
203         }
204         else if ( qName.equals( "version" ) && currentParent.equals( "item" ) )
205         {
206             issue.setVersion( currentElement.toString().trim() );
207         }
208         else if ( qName.equals( "version" ) && currentParent.equals( "build-info" ) )
209         {
210             jiraVersion = currentElement.toString().trim();
211         }
212         else if ( qName.equals( "fixVersion" ) )
213         {
214             issue.addFixVersion( currentElement.toString().trim() );
215         }
216         else if ( qName.equals( "component" ) )
217         {
218             issue.addComponent( currentElement.toString().trim() );
219         }
220         else if ( qName.equals( "comment" ) )
221         {
222             issue.addComment( currentElement.toString().trim() );
223         }
224         else if ( qName.equals( "title" ) && currentParent.equals( "item" ) )
225         {
226             issue.setTitle( currentElement.toString().trim() );
227         }
228         else if ( qName.equals( "created" ) && currentParent.equals( "item" ) && sdf != null )
229         {
230             try
231             {
232                 issue.setCreated( sdf.parse( currentElement.toString().trim() ) );
233             }
234             catch ( ParseException e )
235             {
236                 log.warn( "Element \"Created\". " + e.getMessage() + ". Using the pattern \"" + datePattern + "\"" );
237             }
238         }
239         else if ( qName.equals( "updated" ) && currentParent.equals( "item" ) && sdf != null )
240         {
241             try
242             {
243                 issue.setUpdated( sdf.parse( currentElement.toString().trim() ) );
244             }
245             catch ( ParseException e )
246             {
247                 log.warn( "Element \"Updated\". " + e.getMessage() + ". Using the pattern \"" + datePattern + "\"" );
248             }
249         }
250 
251         currentElement.setLength( 0 );
252     }
253 
254     public void characters( char[] buf, int offset, int len )
255         throws SAXException
256     {
257         currentElement.append( buf, offset, len );
258     }
259 
260     public List<Issue> getIssueList()
261     {
262         return Collections.unmodifiableList( this.issueList );
263     }
264 
265     public String getJiraVersion()
266     {
267         return jiraVersion;
268     }
269 }