1 /***
2 * Created by IntelliJ IDEA.
3 * User: Lennart
4 * Date: 24-okt-2003
5 * Time: 16:17:50
6 */
7 package be.proteomics.maven.distrib;
8
9 import org.apache.maven.repository.GenericArtifact;
10 import org.apache.maven.project.Dependency;
11
12 import java.io.*;
13 import java.util.*;
14 import java.text.SimpleDateFormat;
15
16
17 /*
18 * CVS information:
19 *
20 * $Revision: 1.3 $
21 * $Date: 2004/03/24 14:39:41 $
22 */
23
24 /***
25 * This class implements a Java Bean for the distrib plugin in Maven that generates a page for
26 * downloading distributions of the software. <br />
27 * The main responsability for this bean is to create the list of files, sort them in descending order
28 * and create a String with the XDOC code for the table that will hold the links and a description.
29 *
30 * @author Lennart Martens
31 */
32 public class DistribBean {
33
34 /***
35 * The String to hold the folder name retrieved by the Jelly script.
36 */
37 private String iFolder = null;
38
39 /***
40 * The String to hold the project ID as retrieved by the Jelly script.
41 */
42 private String iProjectID = null;
43
44 /***
45 * The file that all output will be written to by the Jelly script.
46 */
47 private String iDestinationFile = null;
48
49 /***
50 * The cached contents of the outputfile.
51 */
52 private String iDestinationFileContents = null;
53
54 /***
55 * The SimpleDateFormatter.
56 */
57 private SimpleDateFormat iSDF = null;
58
59 /***
60 * Default public constructor, as stipulated in the JavaBean contract.
61 */
62 public DistribBean() {}
63
64 /***
65 * The work horse of this bean. After construction of the bean, this is the thing to do.
66 * This method fills out the default last modified date format: 'dd/MM/yyyy'.
67 *
68 * @param aFolder String with the folder retrieved by the Jelly script.
69 * @param aID String with the project ID (as used in the artifacts).
70 * @param aDestinationFile outputfile for the generated HTML document.
71 */
72 public String createDistribTable(String aFolder, String aID, String aDestinationFile) {
73 return this.createDistribTable(aFolder, aID, aDestinationFile, "dd/MM/yyyy");
74 }
75
76 /***
77 * The work horse of this bean. After construction of the bean, this is the thing to do.
78 *
79 * @param aFolder String with the folder retrieved by the Jelly script.
80 * @param aID String with the project ID (as used in the artifacts).
81 * @param aDestinationFile outputfile for the generated HTML document.
82 * @param aDateFormat String with the date format desired.
83 */
84 public String createDistribTable(String aFolder, String aID, String aDestinationFile, String aDateFormat) {
85 // Just to separate the output block of this script from all others.
86 System.out.println("");
87 iFolder = aFolder.replace('//', '/');
88 iProjectID = aID;
89 iDestinationFile = aDestinationFile;
90 this.cacheDestinationFile();
91 System.out.println(" [distrib] Creating distribution report based on the project jars in the '" + iFolder + "' folder.");
92 iSDF = new SimpleDateFormat(aDateFormat);
93 System.out.println(" [distrib] Using date format: " + aDateFormat + ".");
94 return this.generateHTMLTable();
95 }
96
97 /***
98 * This method creates the table with the direct download links for all the dependencies.
99 *
100 * @param aDependencies Collection with the dependencies from the Jelly script.
101 * @return String with the HTML code for the dependencies table.
102 */
103 public String createDependenciesTable(Collection aDependencies) {
104 StringBuffer result = new StringBuffer();
105 // See if there are any dependencies.
106 if(aDependencies != null && aDependencies.size() > 0) {
107 System.out.println(" [distrib] " + aDependencies.size() + " dependencies found. Creating table of links.");
108 result.append("\n\n\n<table>\n <tr>\n <th>Direct download link</th>\n <th>Project homepage link</th>\n </tr>\n");
109
110 Iterator iter = aDependencies.iterator();
111 while(iter.hasNext()) {
112 GenericArtifact ga = (GenericArtifact)iter.next();
113 String filename = ga.getFile().getName();
114 Dependency dp = ga.getDependency();
115 String description = dp.getGroupId();
116 String url = dp.getUrl();
117 result.append(" <tr>\n");
118 result.append(" <td><a href=\"" + filename + "\">" + filename + "</a></td>\n");
119 result.append(" <td><a href=\""+ url + "\">" + description + "</a></td>\n");
120 result.append(" </tr>\n");
121 }
122
123 result.append("</table>\n\n\n");
124 } else {
125 // No dependencies for this project.
126 System.out.println(" [distrib] No dependencies found. Omitting table of links.");
127 result.append("<i>No dependencies defined in this project</i>");
128 }
129
130 return result.toString();
131 }
132
133 /***
134 * This method attempts to find the destination file, and when found, reads it into the
135 * iDestinationFileContents String variable. If the file was not found, or there was an
136 * error, this variable will be null.
137 */
138 private void cacheDestinationFile() {
139 // Try to get our hands on the output file.
140 File output = new File(iDestinationFile);
141 if(output.exists()) {
142 StringBuffer temp = new StringBuffer();
143 // Succes! The output file already is present!
144 // See if we can find an existing description for this distribution filename.
145 try {
146 BufferedReader br = new BufferedReader(new FileReader(iDestinationFile));
147 String line = null;
148 while((line = br.readLine()) != null) {
149 temp.append(line + "\n");
150 }
151 iDestinationFileContents = temp.toString();
152 System.out.println(" [distrib] Existing output file found and read.");
153 br.close();
154 } catch(IOException ioe) {
155 System.err.println(" [distrib] IOException while attempting to read '" + iDestinationFile + "': " + ioe.getMessage());
156 }
157 } else {
158 System.out.println(" [distrib] No existing output file found.");
159 }
160 }
161
162
163 /***
164 * This method takes care of generating the HTML code for the table.
165 *
166 * @return String with the HTML code for the table.
167 */
168 private String generateHTMLTable() {
169 StringBuffer table = new StringBuffer("\n\n\n<table>\n <tr>\n <th>File download link</th>\n <th>Last modified on</th>\n" +
170 " <th>Description</th>\n </tr>\n");
171 // Okay, let's find all files in the specified folder.
172 File folder = new File(iFolder);
173 if(!folder.exists()) {
174 try {
175 System.err.println(" [distrib] The folder you specified (" + folder.getCanonicalPath() + ") was not created by the Jelly script! Empty distributions table will be included.");
176 } catch(IOException ioe) {
177 ioe.printStackTrace();
178 }
179 } else if(!folder.isDirectory()) {
180 System.err.println(" [distrib] The path you specified for writing the XDOC distribution xml page is not a folder! Empty distributions table will be included.");
181 } else {
182 // Now we can do something useful.
183 File[] toInclude = folder.listFiles(new FilenameFilter() {
184 public boolean accept(File dir, String name) {
185 boolean result = false;
186 // Filter on 'projectID'*'.jar'.
187 if(name.startsWith(iProjectID) && name.endsWith(".jar")) {
188 result = true;
189 }
190 return result;
191 }
192 });
193 // Let's sort the array!
194 Arrays.sort(toInclude, new InnerDescendingFileVersionComparator());
195 // Array sorted! The most recent one should go on top, so...
196 for(int i = 0; i < toInclude.length; i++) {
197 this.addTableRow(table, toInclude[i]);
198 }
199 }
200 table.append("</table>\n\n\n");
201 return table.toString();
202 }
203
204 /***
205 * This method will add the row tag for the specified file to the specified StringBuffer.
206 * Note that this StringBufefr should already have an opening <table> tag set.
207 *
208 * @param aTable StringBuffer to add the <tr> element to.
209 * @param aFile File to add to the table.
210 */
211 private void addTableRow(StringBuffer aTable, File aFile) {
212 String filename = aFile.getName();
213 String description = this.attemptDescriptionRetrieval(filename);
214 aTable.append(" <tr>\n");
215 aTable.append(" <td><a href=\"" + filename + "\">" + filename + "</a></td>\n");
216 aTable.append(" <td>" + iSDF.format(new Date(aFile.lastModified())) + "</td>");
217 // Note the '<!-- filename -->' and '<!-- /filename -->' tags to demarcate the description.
218 // These can later be used to retrieve edited descriptions.
219 aTable.append(" <td><!-- " + filename + " -->" + description + "<!-- /" + filename + " --></td>\n");
220 aTable.append(" </tr>\n");
221 }
222
223 /***
224 * This method attempts to recall an existing description for the specified file. It will
225 * return the description found if succesfull, or 'aFilename + " version."' otherwise.
226 *
227 * @param aFilename String with the filename.
228 * @return String with the description (if found), 'aFilename + " version."' otherwise.
229 */
230 private String attemptDescriptionRetrieval(String aFilename) {
231 // Start by filling out the default value for the description.
232 String result = aFilename + " version.";
233 // See if the output file was cached. If it wasn't, it is either absent or unreadable.
234 if(iDestinationFileContents != null) {
235 // Okay, in getting here, we can search for the filename in the cached contents of the
236 // output file.
237 int start = iDestinationFileContents.indexOf("<!-- " + aFilename + " -->");
238 int descriptionStart = start + aFilename.length() + 9;
239 int end = iDestinationFileContents.indexOf("<!-- /" + aFilename + " -->", descriptionStart);
240 // Note that we require the presence of both start and end tags, and that the start tag
241 // should be positioned before the end tag in such a way that they are at least continuous.
242 // Of course, it would be much more fun if there were something useful in between these two tags.
243 if(start >= 0 && end >= 0 && (descriptionStart < end)) {
244 // Found the tags! Let's go get the description!
245 result = iDestinationFileContents.substring(descriptionStart, end).trim();
246 System.out.println(" [distrib] Found existing description tag for '" + aFilename + "'!");
247 } else {
248 // Tell the user.
249 System.out.println(" [distrib] Existing description tag for '" + aFilename + "' was not found.");
250 }
251 }
252 return result;
253 }
254
255 /***
256 * The comparator that sorts Maven-generated jars files in descending according to
257 * their version number.
258 */
259 private class InnerDescendingFileVersionComparator implements Comparator {
260
261 /***
262 * This method will decide which of o1, o2 has precedence over the other.
263 *
264 * @param o1 Object to compare with o2.
265 * @param o2 Object to compare with o1.
266 * @return int with the result of the comparison.
267 */
268 public int compare(Object o1, Object o2) {
269 int result = 0;
270 String a = ((File)o1).getName();
271 String b = ((File)o2).getName();
272 //System.out.println(" ** [distrib] Starting with: '" + a + "' and '" + b + "'.");
273 // Remove the leading project id and trailing '.jar', since this is
274 // a common feature (we've selected for this with the FilenameFilter).
275 a = a.substring(iProjectID.length(), a.lastIndexOf(".jar"));
276 b = b.substring(iProjectID.length(), b.lastIndexOf(".jar"));
277 // Leading '-' must be removed as well.
278 while(a.startsWith("-")) {
279 a = a.substring(1);
280 }
281 while(b.startsWith("-")) {
282 b = b.substring(1);
283 }
284 //System.out.println(" ** [distrib] Transformed into: '" + a + "' and '" + b + "'.");
285 // Break the filenames down in their constituent parts.
286 // and evaluate them.
287 // What we do is we check the part up to the first detected '.'
288 // then see if we have a difference. If we have one, calculate
289 // difference and quit.
290 // If we don't have a difference, find the next value up to the next
291 // '.' (or end of the String). Etc.
292 boolean lbContinue = true;
293 while(lbContinue) {
294 // If both a and b are empty Strings, we were/are unable to find a difference.
295 // This should not occur, since it means that the two initial files had the same name
296 // but we'll check anyway.
297 if(a.equals("") && b.equals("")) {
298 result = 0;
299 lbContinue = false;
300 continue;
301 }
302 // tempA equals a, in case there is no '.' left in a,
303 // tempA holds this value.
304 String tempA = a;
305 int startA = -1;
306 if((startA = a.indexOf(".")) >= 0) {
307 // tempA is the element up to the first '.'.
308 tempA = a.substring(0, startA);
309 // Truncate a to hold only the remainder after the first found '.'
310 a = a.substring(startA);
311 // If a holds more than just the '.', remove the '.'.
312 if(a.length() > 1) {
313 a = a.substring(1);
314 } else {
315 // a is just an empty String.
316 a = "";
317 }
318 } else {
319 a = "";
320 }
321 // Same for b.
322 String tempB = b;
323 int startB = -1;
324 if((startB = b.indexOf(".")) >= 0) {
325 // tempB is the element up to the first '.'.
326 tempB = b.substring(0, startB);
327 // Truncate a to hold only the remainder after the first found '.'
328 b = b.substring(startB);
329 // If b holds more than just the '.', remove the '.'.
330 if(b.length() > 1) {
331 b = b.substring(1);
332 } else {
333 // b is just an empty String.
334 b = "";
335 }
336 } else {
337 b = "";
338 }
339 //System.out.println(" ** [distrib ] tempA (a): '" + tempA + "' (" + a + ") and tempB (b): '" + tempB + "' (" + b + ").");
340 // Okay, compare tempA and tempB.
341 // See what the Stringcompare tells us.
342 int tempResult = tempA.compareTo(tempB);
343 if(tempResult != 0) {
344 result = tempResult;
345 lbContinue = false;
346 continue;
347 } else {
348 // Just go on with the show.
349 }
350 }
351 // Descending order is requested.
352 return -result;
353 }
354 }
355 }
This page was automatically generated by Maven