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.maven.plugins.changes;
20  
21  import java.io.IOException;
22  import java.io.Writer;
23  import java.text.DateFormat;
24  import java.text.ParseException;
25  import java.util.ArrayList;
26  import java.util.Date;
27  import java.util.List;
28  import java.util.Locale;
29  import java.util.ResourceBundle;
30  
31  import com.rometools.rome.feed.synd.SyndContent;
32  import com.rometools.rome.feed.synd.SyndContentImpl;
33  import com.rometools.rome.feed.synd.SyndEntry;
34  import com.rometools.rome.feed.synd.SyndEntryImpl;
35  import com.rometools.rome.feed.synd.SyndFeed;
36  import com.rometools.rome.feed.synd.SyndFeedImpl;
37  import com.rometools.rome.io.FeedException;
38  import com.rometools.rome.io.SyndFeedOutput;
39  import org.apache.maven.doxia.util.DoxiaUtils;
40  import org.apache.maven.plugins.changes.model.Release;
41  
42  /**
43   * @author ltheussl
44   */
45  public class FeedGenerator {
46      private final ResourceBundle rbundle;
47  
48      private final SyndFeed feed;
49  
50      private String link;
51  
52      private String title;
53  
54      private String author;
55  
56      private DateFormat dateFormat;
57  
58      /**
59       * Initialize feedGenerator for a given locale.
60       *
61       * @param locale a locale for i18n
62       */
63      public FeedGenerator(final Locale locale) {
64          this.feed = new SyndFeedImpl();
65          this.rbundle = ResourceBundle.getBundle(
66                  "changes-report", locale, this.getClass().getClassLoader());
67      }
68  
69      /**
70       * The author of the feed.
71       *
72       * @return the author
73       */
74      public String getAuthor() {
75          return author;
76      }
77  
78      /**
79       * Set the author of the feed.
80       *
81       * @param author not null
82       */
83      public void setAuthor(final String author) {
84          this.author = author.trim(); // this also assures that author is not null.
85      }
86  
87      /**
88       * The title of the feed.
89       *
90       * @return the title
91       */
92      public String getTitle() {
93          return title;
94      }
95  
96      /**
97       * Set the title of the feed.
98       *
99       * @param title not null
100      */
101     public void setTitle(final String title) {
102         this.title = title.trim(); // this also assures that title is not null.
103     }
104 
105     /**
106      * The DateFormat.
107      *
108      * @return may be null
109      */
110     public DateFormat getDateFormat() {
111         return dateFormat;
112     }
113 
114     /**
115      * Set the date format. This should match the date format used for the release dates in changes.xml.
116      *
117      * @param dateFormat may be null
118      */
119     public void setDateFormat(final DateFormat dateFormat) {
120         this.dateFormat = dateFormat;
121     }
122 
123     /**
124      * The main link of the feed.
125      *
126      * @return the link
127      */
128     public String getLink() {
129         return link;
130     }
131 
132     /**
133      * Set the main link of the feed.
134      *
135      * @param link not null
136      */
137     public void setLink(final String link) {
138         this.link = link.trim(); // this also assures that link is not null.
139     }
140 
141     /**
142      * Determine if a given feed type is supported. The currently supported values are:
143      * <code>"rss_0.9", "rss_0.91N" (RSS 0.91 Netscape), "rss_0.91U" (RSS 0.91 Userland),
144      * "rss_0.92", "rss_0.93", "rss_0.94", "rss_1.0", "rss_2.0", "atom_0.3", "atom_1.0"</code>.
145      *
146      * @param type the feed type to check. May be null.
147      * @return true if the given type is supported by the rome library, false otherwise
148      */
149     public boolean isSupportedFeedType(final String type) {
150         return getSupportedFeedTypes().contains(type);
151     }
152 
153     /**
154      * A List of supported feed types.
155      *
156      * @return a List of supported feed types
157      * @see #isSupportedFeedType(java.lang.String)
158      */
159     public List<String> getSupportedFeedTypes() {
160         return feed.getSupportedFeedTypes();
161     }
162 
163     /**
164      * Extract a feed and export it to a Writer.
165      *
166      * @param releases the List of Releases. Only the last release is used in the feed.
167      * @param feedType The type of the feed to generate. See {@link #isSupportedFeedType(java.lang.String)} for
168      *            supported values.
169      * @param writer a Writer. Note that this is not flushed nor closed upon exit.
170      * @throws IOException if an error occurs during export
171      */
172     public void export(final List<Release> releases, final String feedType, final Writer writer) throws IOException {
173         feed.setFeedType(feedType);
174         feed.setTitle(title);
175         feed.setAuthor(author);
176         feed.setPublishedDate(new Date());
177         feed.setLink(link);
178         feed.setDescription(rbundle.getString("report.changes.text.rssfeed.description"));
179         feed.setLanguage(rbundle.getLocale().getLanguage());
180         feed.setEntries(getEntries(releases));
181 
182         try {
183             new SyndFeedOutput().output(feed, writer);
184         } catch (FeedException ex) {
185             throw new IOException(ex.getMessage(), ex);
186         }
187     }
188 
189     private List<SyndEntry> getEntries(final List<Release> releases) {
190         final List<SyndEntry> entries = new ArrayList<>(1);
191 
192         if (!releases.isEmpty()) {
193             final Release release = releases.get(0); // TODO: is this guaranteed to be the latest?
194 
195             final SyndEntry entry = new SyndEntryImpl();
196             entry.setTitle(release.getVersion());
197             entry.setLink(link + "#" + DoxiaUtils.encodeId(release.getVersion()));
198             entry.setDescription(getSyndContent(release));
199             entry.setPublishedDate(getDate(release.getDateRelease(), dateFormat));
200 
201             entries.add(entry);
202         }
203 
204         return entries;
205     }
206 
207     private static SyndContent getSyndContent(final Release release) {
208         final SyndContent syndContent = new SyndContentImpl();
209         syndContent.setType("text/html");
210 
211         final StringBuilder sb = new StringBuilder(512);
212 
213         final String description = release.getDescription();
214 
215         if (description != null && !description.trim().isEmpty()) {
216             sb.append("<p>").append(description).append("</p>");
217         }
218 
219         sb.append("<p>Version ").append(release.getVersion()).append(" is available with ");
220         sb.append(release.getActions().size()).append(" fixed issues.</p>");
221 
222         syndContent.setValue(sb.toString());
223 
224         return syndContent;
225     }
226 
227     private static Date getDate(final String dateRelease, final DateFormat dateFormat) {
228         if (dateFormat == null) {
229             return new Date();
230         }
231 
232         try {
233             return dateFormat.parse(dateRelease);
234         } catch (ParseException ex) {
235             return new Date();
236         }
237     }
238 }