1 /*******************************************************************************
2  * Copyright (c) 2005, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.releng.services.rss;
12 
13 import java.io.File;
14 import java.io.FileInputStream;
15 import java.io.FileNotFoundException;
16 import java.io.FileOutputStream;
17 import java.io.IOException;
18 import java.net.MalformedURLException;
19 import java.net.URL;
20 
21 import org.apache.tools.ant.BuildException;
22 import org.apache.tools.ant.Task;
23 import org.apache.tools.ant.taskdefs.ExecTask;
24 
25 import org.eclipse.releng.generators.rss.RSSFeedUpdateEntryTask;
26 import org.eclipse.releng.util.rss.Messages;
27 import org.eclipse.releng.util.rss.RSSFeedUtil;
28 
29 /**
30  * Parameters:
31  *   debug - more output to console - eg., 0|1|2
32  *
33  *   file - path to the XML file that will be published - eg., /path/to/file.to.publish.xml
34  *   feedURL - URL of the feed where it will be published - eg., http://servername/path/to/feed.xml
35  *
36  *   feedWatchActions - semi-comma-separated list of triplets:
37  *   	(Xpath to watch for); (what to execute if condition is met); (commandline args to the executable)...
38  *   	eg., to watch for ANY change in the feed and respond by sending email
39  *   		/*[name() = 'feed']/*[name() = 'updated']/text(); sendEmailAlert.sh; null
40  *      eg., to watch for ANY changes in the current build
41  *   		//*[name() = 'entry'][1]/*[name() = 'updated']/text(); sendEmailAlert.sh; null
42  *      eg., to watch for changes in the current build's performance test results on linux-gtk
43  *      	//*[name() = 'entry'][1]/*[name() = 'summary']/*[@type = 'performance'][1]/*[name() = 'results'][@os = 'linux'][@ws = 'gtk']/text(); sendEmailAlert.sh; null
44  *
45  * @author nickb
46  *
47  */
48 public class RSSFeedWatcherTask extends Task {
49 
50   private int debug = 0;
51 
52   private static final String CL = ":"; //$NON-NLS-1$
53   private static final String DOT = "."; //$NON-NLS-1$
54   private static final String NS = ""; //$NON-NLS-1$
55   private static final String SP = " "; //$NON-NLS-1$
56 
57   private static final String splitter = "[;\t\r\n]+"; //$NON-NLS-1$
58 
59   private static final String feedWatchActionError = "feedWatchAction.Error"; //$NON-NLS-1$
60   private static final String feedWatchActionOuput = "feedWatchAction.Output"; //$NON-NLS-1$
61   private static final String feedWatchActionResult = "feedWatchAction.Result"; //$NON-NLS-1$
62   private static final String feedWatchActionNewValue = "feedWatchAction.NewValue"; //$NON-NLS-1$
63   private static final String feedWatchActionOldValue = "feedWatchAction.OldValue"; //$NON-NLS-1$
64   private static final String feedWatchActionTheValue = "feedWatchAction.TheValue"; //$NON-NLS-1$
65 
66   private static final RSSFeedUtil util = new RSSFeedUtil();
67 
68   //required fields
69   private File file;
70   private File tmpFile;
71   private String feedURL;
72   private String[] feedWatchActions = new String[] {};
73 
74   //optional
setDebug(int debug)75   public void setDebug(int debug) { this.debug = debug; }
76 
77   //required
setFile(String file)78   public void setFile(String file) {
79     if (!isNullString(file)) {
80       this.file = new File(file);
81       this.tmpFile = new File(file + ".tmp");  //$NON-NLS-1$
82     }
83   }
setFeedURL(String feedURL)84   public void setFeedURL(String feedURL) {
85     if (isNullString(feedURL))
86     { System.err.println(Messages.getString("RSSFeedCommon.FeedURLError")); }  //$NON-NLS-1$
87     else
88     { this.feedURL = feedURL; }
89   }
setFeedWatchActions(String feedWatchActions)90   public void setFeedWatchActions(String feedWatchActions) {
91     int missingActions = 0;
92     if (!isNullString(feedWatchActions)) {
93       this.feedWatchActions = feedWatchActions.split(splitter);
94       missingActions = this.feedWatchActions.length % 3; if (missingActions > 0) { missingActions = 3 - missingActions; }
95     }
96     if (missingActions > 0) {
97       for (int i = 0; i < missingActions; i++)
98       {
99         System.out.println((i==0 && missingActions==2 ? Messages.getString("RSSFeedWatcherTask.WarningNoScriptAction") : Messages.getString("RSSFeedWatcherTask.WarningNoCommandlineParams")) + SP + feedWatchActions ); //$NON-NLS-1$ //$NON-NLS-2$
100         feedWatchActions += "; null"; //$NON-NLS-1$
101       }
102       this.feedWatchActions = feedWatchActions.split(splitter);
103     }
104   }
105 
106   // The method executing the task
execute()107   public void execute() throws BuildException {
108     if (debug>0) { util.setDebug(debug); }
109     if (file==null || !file.exists() || !file.isFile()) {
110       // if there's no local copy of the feed, get a copy, then exit with instructions
111       downloadFeed(file,debug>=0);
112       System.out.println(Messages.getString("RSSFeedWatcherTask.PleaseRunThisTaskLater") + SP + file); //$NON-NLS-1$
113       System.out.println(Messages.getString("RSSFeedWatcherTask.ToTheLatestVersion") + SP + feedURL); //$NON-NLS-1$
114     } else {
115       if (feedWatchActions==null || feedWatchActions.length<1) {
116         System.err.println(Messages.getString("RSSFeedWatcherTask.ErrorNoWatchActions")); //$NON-NLS-1$
117       } else {
118         checkFeed();
119       }
120     }
121   }
122 
checkFeed()123   private void checkFeed() {
124     if (file.isDirectory()) {
125       System.err.println(Messages.getString("RSSFeedWatcherTask.ErrorDestinationFileIsADirectory")); //$NON-NLS-1$
126     } else {
127       downloadFeed(tmpFile,debug>0);
128     }
129 
130     if (tmpFile.isFile()) {
131       if (debug>0) { System.out.println(Messages.getString("RSSFeedWatcherTask.Compare") + SP + file + Messages.getString("RSSFeedWatcherTask.with") + tmpFile + CL); } //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
132 
133       RSSFeedUpdateEntryTask oldFeedWatcher = null;
134       RSSFeedUpdateEntryTask newFeedWatcher = null;
135       int j=0;
136 
137       for (int i = 0; i < feedWatchActions.length; i+=3)
138       {
139         String xpath = feedWatchActions[i].trim();
140         String action = feedWatchActions[i+1].trim();
141         String commandline = feedWatchActions[i+2].trim();
142 
143         oldFeedWatcher = new RSSFeedUpdateEntryTask();
144         oldFeedWatcher.setFile(file.toString());
145         if (debug>0) { oldFeedWatcher.setDebug(debug); }
146         oldFeedWatcher.setXpath(xpath);
147         oldFeedWatcher.execute();
148 
149         if (oldFeedWatcher.getFoundNode() != null) {
150           newFeedWatcher = new RSSFeedUpdateEntryTask();
151           newFeedWatcher.setFile(tmpFile.toString());
152           if (debug>0) { newFeedWatcher.setDebug(debug); }
153           newFeedWatcher.setXpath(xpath);
154           newFeedWatcher.execute();
155 
156           String oldContent = oldFeedWatcher.getFoundNode().getTextContent();
157           String newContent = newFeedWatcher.getFoundNode().getTextContent();
158 
159           if (debug>1) {
160             System.out.println(Messages.getString("RSSFeedWatcherTask.GotOldNodeContents") + CL + SP + oldContent); //$NON-NLS-1$
161             System.out.println(Messages.getString("RSSFeedWatcherTask.GotNewNodeContents") + CL + SP + newContent); //$NON-NLS-1$
162           }
163 
164           if (!"null".equals(action)) { //$NON-NLS-1$
165             commandline =
166               (debug>0?"-debug " + debug + SP:NS) + ("null".equals(commandline)?NS:commandline) + //$NON-NLS-1$ //$NON-NLS-2$
167               " -feedURL " + feedURL + //$NON-NLS-1$
168               " -xpath \"" + xpath + "\"" + //$NON-NLS-1$ //$NON-NLS-2$
169               " -oldvalue \"" + oldContent + "\"" + //$NON-NLS-1$ //$NON-NLS-2$
170               " -newvalue \"" + newContent + "\""; //$NON-NLS-1$ //$NON-NLS-2$
171           }
172 
173           // store actual value - either the changed value or the original value (if unchanged)
174           this.getProject().setProperty(feedWatchActionTheValue + DOT + j,!isNullString(newContent)?newContent:oldContent);
175 
176           if (newFeedWatcher.getFoundNode() == null || // changed from exists to not exists, or
177               !oldContent.equals(newContent) // node has changed
178           ) {
179             // collect property from newNode and pass it to THIS task so that the local ant script can see it
180             if (!isNullString(oldContent)) { this.getProject().setProperty(feedWatchActionOldValue + DOT + j,oldContent); }
181             if (!isNullString(newContent)) { this.getProject().setProperty(feedWatchActionNewValue + DOT + j,newContent); }
182 
183             if (!"null".equals(action)) { //$NON-NLS-1$
184               System.out.println(Messages.getString("RSSFeedWatcherTask.RunExecTask") + CL + SP + action + SP + commandline); //$NON-NLS-1$
185               ExecTask exec = util.runExecTask((new File(action)).getAbsolutePath(), commandline, null);
186 
187               // collect properties from exec task and pass them to THIS task so that the local ant script can see them
188               String out = null;
189 
190               out = exec.getProject().getProperty(RSSFeedUtil.RUN_EXEC_TASK_ERROR);
191               if (!isNullString(out)) { this.getProject().setProperty(feedWatchActionError + DOT + j, out); }
192 
193               out = exec.getProject().getProperty(RSSFeedUtil.RUN_EXEC_TASK_RESULT);
194               if (!isNullString(out)) { this.getProject().setProperty(feedWatchActionOuput + DOT + j, out); }
195 
196               out = exec.getProject().getProperty(RSSFeedUtil.RUN_EXEC_TASK_RESULT);
197               if (!RSSFeedUtil.EXPECTED_RESULT.equals(out)) { this.getProject().setProperty(feedWatchActionResult + DOT + j, out); }
198             }
199           } else {
200             System.out.println(Messages.getString("RSSFeedWatcherTask.NodeUnchanged")); //$NON-NLS-1$
201           }
202         } else {
203           System.out.println(Messages.getString("RSSFeedWatcherTask.NodeNotFound")); //$NON-NLS-1$
204         }
205         j++;
206       }
207 
208       try
209       {
210         RSSFeedUtil.transferData(new FileInputStream(tmpFile), new FileOutputStream(file));
211         tmpFile.deleteOnExit();
212       }
213       catch (FileNotFoundException e)
214       {
215         e.printStackTrace();
216       }
217       catch (IOException e)
218       {
219         e.printStackTrace();
220       }
221     }
222   }
223 
downloadFeed(File destFile, boolean verbose)224   private void downloadFeed(File destFile, boolean verbose)
225   {
226     try
227     {
228       if (verbose) {
229         System.out.println(Messages.getString("RSSFeedWatcherTask.Download") + CL + SP + feedURL); //$NON-NLS-1$
230         System.out.println(Messages.getString("RSSFeedWatcherTask.To") + CL + SP + destFile + SP); //$NON-NLS-1$
231       }
232       RSSFeedUtil.transferData((new URL(feedURL)).openStream(), new FileOutputStream(destFile));
233       if (verbose) {
234         System.out.println(Messages.getString("RSSFeedWatcherTask.Done")); //$NON-NLS-1$
235         System.out.println(SP);
236       }
237     }
238     catch (MalformedURLException e)
239     {
240       e.printStackTrace();
241     }
242     catch (FileNotFoundException e)
243     {
244       e.printStackTrace();
245     }
246     catch (IOException e)
247     {
248       e.printStackTrace();
249     }
250   }
251 
isNullString(String str)252   private static boolean isNullString(String str)
253   {
254     return RSSFeedUtil.isNullString(str);
255   }
256 
257 }