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 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.setCopyright( );
181         // feed.setEncoding();
182         feed.setEntries(getEntries(releases));
183 
184         try {
185             new SyndFeedOutput().output(feed, writer);
186         } catch (FeedException ex) {
187             throw new IOException(ex.getMessage(), ex);
188         }
189     }
190 
191     private List<SyndEntry> getEntries(final List<Release> releases) {
192         final List<SyndEntry> entries = new ArrayList<>(1);
193 
194         if (releases.size() > 0) {
195             final Release release = releases.get(0); // TODO: is this guaranteed to be the latest?
196 
197             final SyndEntry entry = new SyndEntryImpl();
198             entry.setTitle(release.getVersion());
199             entry.setLink(link + "#" + DoxiaUtils.encodeId(release.getVersion()));
200             entry.setDescription(getSyndContent(release));
201             entry.setPublishedDate(getDate(release.getDateRelease(), dateFormat));
202 
203             entries.add(entry);
204         }
205 
206         return entries;
207     }
208 
209     private static SyndContent getSyndContent(final Release release) {
210         final SyndContent syndContent = new SyndContentImpl();
211         syndContent.setType("text/html");
212 
213         final StringBuilder sb = new StringBuilder(512);
214 
215         final String description = release.getDescription();
216 
217         if (description != null && description.trim().length() > 0) {
218             sb.append("<p>").append(description).append("</p>");
219         }
220 
221         sb.append("<p>Version ").append(release.getVersion()).append(" is available with ");
222         sb.append(release.getActions().size()).append(" fixed issues.</p>");
223 
224         syndContent.setValue(sb.toString());
225 
226         return syndContent;
227     }
228 
229     private static Date getDate(final String dateRelease, final DateFormat dateFormat) {
230         if (dateFormat == null) {
231             return new Date();
232         }
233 
234         try {
235             return dateFormat.parse(dateRelease);
236         } catch (ParseException ex) {
237             return new Date();
238         }
239     }
240 }