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.generators.rss; 12 13 import java.io.File; 14 import java.io.FileNotFoundException; 15 import java.io.IOException; 16 import java.io.PrintStream; 17 import java.util.Date; 18 19 import javax.xml.parsers.DocumentBuilder; 20 import javax.xml.parsers.DocumentBuilderFactory; 21 import javax.xml.parsers.ParserConfigurationException; 22 import javax.xml.transform.Transformer; 23 import javax.xml.transform.TransformerException; 24 import javax.xml.transform.dom.DOMSource; 25 import javax.xml.transform.stream.StreamResult; 26 import javax.xml.xpath.XPath; 27 import javax.xml.xpath.XPathConstants; 28 import javax.xml.xpath.XPathExpressionException; 29 import javax.xml.xpath.XPathFactory; 30 31 import org.apache.tools.ant.BuildException; 32 import org.apache.tools.ant.Task; 33 import org.apache.tools.ant.util.DateUtils; 34 import org.w3c.dom.Attr; 35 import org.w3c.dom.Document; 36 import org.w3c.dom.Element; 37 import org.w3c.dom.Node; 38 import org.w3c.dom.NodeList; 39 import org.w3c.dom.Text; 40 import org.xml.sax.SAXException; 41 42 import org.eclipse.releng.util.rss.Messages; 43 import org.eclipse.releng.util.rss.RSSFeedUtil; 44 45 /** 46 * Parameters: 47 * debug - more output to console - eg., 0|1|2 48 * 49 * file - path to the XML file that will be read - eg., /path/to/file.to.read.xml 50 * xpath - xpath string representing the object to modify 51 * replacement - string to use as replacement 52 * 53 * @author nickb 54 * 55 */ 56 public class RSSFeedUpdateEntryTask extends Task { 57 58 private int debug = 0; 59 60 private static final String now = getTimestamp(); 61 62 private static final XPath xp = XPathFactory.newInstance().newXPath(); 63 64 private static final String NS = ""; //$NON-NLS-1$ 65 private static final String SEP = "----"; //$NON-NLS-1$ 66 private static final String SP = " "; //$NON-NLS-1$ 67 68 //required fields 69 private File file; 70 71 private String xpath; 72 private String replacement; 73 74 private Transformer transformer = null; 75 76 private boolean isNodeFound = false; 77 private boolean isNodeChanged = false; 78 private Node foundNode = null; 79 80 //optional setDebug(int debug)81 public void setDebug(int debug) { this.debug = debug; } 82 83 //required fields setFile(String file)84 public void setFile(String file) { 85 if (isNullString(file)) 86 { System.err.println(Messages.getString("RSSFeedCommon.FileError")); } //$NON-NLS-1$ 87 else 88 { this.file = new File(file); } 89 } setXpath(String xpath)90 public void setXpath(String xpath) { 91 if (isNullString(xpath)) 92 { System.err.println(Messages.getString("RSSFeedCommon.XpathError")); } //$NON-NLS-1$ 93 else 94 { this.xpath = xpath; } 95 } 96 97 //optional - if null, display value found instead of changing it - see RSSFeedGetPropertyTask setReplacement(String replacement)98 public void setReplacement(String replacement) { this.replacement = replacement; } 99 100 // The method executing the task execute()101 public void execute() throws BuildException { 102 if (debug>0) { 103 System.out.println(Messages.getString("RSSFeedUpdateEntryTask.SearchingFor") + SP + xpath + (!isNullString(replacement)?", " + Messages.getString("RSSFeedUpdateEntryTask.ReplacingWith") + " '" + replacement + "'":NS)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ 104 } 105 updateFeedXML(file); // load previous 106 } 107 108 //$ANALYSIS-IGNORE codereview.java.rules.exceptions.RuleExceptionsSpecificExceptions updateFeedXML(File file)109 private void updateFeedXML(File file){ 110 if (file.exists()) { 111 DocumentBuilderFactory documentBuilderFactory=DocumentBuilderFactory.newInstance(); 112 documentBuilderFactory.setNamespaceAware(true); 113 DocumentBuilder documentBuilder=null; 114 try { 115 documentBuilder=documentBuilderFactory.newDocumentBuilder(); 116 } 117 catch (ParserConfigurationException e) { 118 e.printStackTrace(); 119 } 120 Document document=null; 121 try { 122 document=documentBuilder.parse(file); 123 } 124 catch (SAXException e) { 125 e.printStackTrace(); 126 } 127 catch (IOException e) { 128 e.printStackTrace(); 129 } 130 131 try { 132 transformer = RSSFeedAddEntryTask.createTransformer("UTF-8"); //$NON-NLS-1$ 133 } catch (TransformerException e) { 134 e.printStackTrace(); 135 } 136 137 if (!isNullString(replacement)) { 138 setEntryNodeUpdate(document.getDocumentElement()); 139 } 140 Node newNode=findAndReplace(document); 141 if (debug > 1 && newNode != null) { 142 try { 143 System.out.println(SEP); 144 transformer.transform(new DOMSource(newNode),new StreamResult(System.out)); 145 System.out.println(SEP); 146 } 147 catch (TransformerException e) { 148 e.printStackTrace(); 149 } 150 } 151 if (!isNullString(replacement) && newNode != null) { 152 try { 153 transformer.transform(new DOMSource(document),new StreamResult(new PrintStream(file))); 154 } 155 catch (FileNotFoundException e) { 156 e.printStackTrace(); 157 } 158 catch (TransformerException e) { 159 e.printStackTrace(); 160 } 161 } 162 } 163 else { 164 System.out.println(Messages.getString("RSSFeedCommon.RSSFeedFile") + SP + file.toString()+ " "+ Messages.getString("RSSFeedUpdateEntryTask.DoesNotExist")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ 165 } 166 } 167 168 // get/set the desired node getFoundNode()169 public Node getFoundNode() 170 { 171 return this.foundNode; 172 } setFoundNode(Node foundNode)173 private void setFoundNode(Node foundNode) 174 { 175 this.foundNode = foundNode; 176 } 177 178 // has the desired node been found? getNodeFound()179 public boolean getNodeFound() 180 { 181 return this.isNodeFound; 182 } setNodeFound(boolean isNodeFound)183 private void setNodeFound(boolean isNodeFound) 184 { 185 this.isNodeFound = isNodeFound; 186 } 187 188 // has the desired node been changed? getNodeChanged()189 public boolean getNodeChanged() 190 { 191 return this.isNodeChanged; 192 } setNodeChanged(boolean isNodeChanged)193 private void setNodeChanged(boolean isNodeChanged) 194 { 195 this.isNodeChanged = isNodeChanged; 196 } 197 198 /** 199 * Modify an entry: 200 * 201 * <entry> 202 * <title/> 203 * <link href=""/> 204 * <id/> 205 * <updated/> 206 * <summary> 207 * ... 208 * </summary> 209 * </entry> 210 */ findAndReplace(Document document)211 private Node findAndReplace(Document document) { 212 Node parentEntryNode = null; 213 Node aNode = null; 214 if (debug==0) { System.out.print(xpath + (isNullString(replacement)?" = ":" :: ")); } //$NON-NLS-1$ //$NON-NLS-2$ 215 NodeList nodelist = getNodeList(document, xpath); 216 // Process the elements in the nodelist 217 if (nodelist != null && nodelist.getLength()>0) { 218 for (int i=0; i<nodelist.getLength(); i++) { 219 Node node = (Node)nodelist.item(i); 220 switch (node.getNodeType()) 221 { 222 case Node.ATTRIBUTE_NODE : 223 aNode = (Attr)nodelist.item(i); 224 if (debug>0) { System.out.print(Messages.getString("RSSFeedUpdateEntryTask.DebugFoundAttribute")); } //$NON-NLS-1$ 225 break; 226 227 case Node.ELEMENT_NODE : 228 aNode = (Element)nodelist.item(i); 229 if (debug>0) { System.out.print(Messages.getString("RSSFeedUpdateEntryTask.DebugFoundElement")); } //$NON-NLS-1$ 230 break; 231 232 case Node.TEXT_NODE : 233 aNode = (Text)nodelist.item(i); 234 if (debug>0) { System.out.print(Messages.getString("RSSFeedUpdateEntryTask.DebugFoundText")); } //$NON-NLS-1$ 235 break; 236 237 default: 238 aNode = null; 239 break; 240 } 241 if (aNode != null) { 242 setFoundNode(aNode); 243 setNodeFound(true); 244 System.out.print((debug>0?aNode.getNodeName() + " = ":NS) + aNode.getNodeValue()); //$NON-NLS-1$ //$NON-NLS-2$ 245 if (!isNullString(replacement)) { aNode.setTextContent(replacement); } 246 System.out.println(isNullString(replacement)?NS:" => " + replacement); //$NON-NLS-1$ //$NON-NLS-2$ 247 if (debug>0) { 248 try 249 { 250 // write to console 251 System.out.println(SEP); //$NON-NLS-1$ 252 transformer.transform(new DOMSource(getParentNode(document,aNode,null,NS)), new StreamResult(System.out)); //$NON-NLS-1$ 253 System.out.println(SEP); //$NON-NLS-1$ 254 } 255 catch (TransformerException e) 256 { 257 e.printStackTrace(); 258 } 259 } 260 if (!isNullString(replacement)) { 261 parentEntryNode = getParentNode(document, aNode, "entry", NS); //$NON-NLS-1$ //$NON-NLS-2$ 262 setEntryNodeUpdate(parentEntryNode); 263 } 264 } 265 } 266 } else { 267 System.out.println(Messages.getString("RSSFeedUpdateEntryTask.XpathNodeNotFound")); //$NON-NLS-1$ 268 } 269 return parentEntryNode; 270 } 271 getParentNode(Document document, Node nodeIn, String target, String indent)272 private Node getParentNode(Document document, Node nodeIn, String target, String indent) 273 { 274 Node node = nodeIn; 275 if (node.getNodeType() != Node.ELEMENT_NODE) { 276 if (debug>1) { System.out.println(indent + Messages.getString("RSSFeedUpdateEntryTask.DebugGotATNode") + node.getNodeName()); } //$NON-NLS-1$ 277 // get the element for the attrib/text node 278 NodeList nodelist = getNodeList(document, xpath.substring(0, xpath.lastIndexOf("/"))); 279 if (nodelist !=null && nodelist.getLength()>0) 280 { 281 for (int i=0; i<nodelist.getLength(); i++) { 282 node = (Node)nodelist.item(i); 283 break; 284 } 285 } 286 } 287 if (debug>1) { System.out.println(indent + Messages.getString("RSSFeedUpdateEntryTask.DebugGotENode") + node.getNodeName() + " (" + node.getNodeType() + ")"); } //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 288 if (!isNullString(target) && !node.getNodeName().equals(target)) 289 { 290 node = getParentNode(document, node.getParentNode(), target, indent + "_ "); //$NON-NLS-1$ 291 } 292 return node; 293 } 294 getNodeList(Document document, String xpath)295 private NodeList getNodeList(Document document, String xpath) 296 { 297 NodeList nodelist = null; 298 try 299 { 300 xp.reset(); 301 Object o = xp.evaluate(xpath, document, XPathConstants.NODESET); 302 if (o instanceof NodeList) 303 { 304 nodelist = (NodeList)o; 305 } 306 } 307 catch (XPathExpressionException e) 308 { 309 e.printStackTrace(); 310 } 311 return nodelist; 312 } 313 314 //$ANALYSIS-IGNORE codereview.java.rules.exceptions.RuleExceptionsSpecificExceptions setEntryNodeUpdate(Node parentEntryNode)315 private void setEntryNodeUpdate(Node parentEntryNode){ 316 for (Node child=parentEntryNode.getFirstChild(); child != null; child=child.getNextSibling()) { 317 if ("updated".equals(child.getLocalName())) { //$NON-NLS-1$ 318 if (debug > 0) { 319 System.out.println(Messages.getString("RSSFeedCommon.Set") + " <" + child.getLocalName()+ ">"+ now+ "</"+ child.getLocalName()+ ">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ 320 } 321 ((Element)child).setTextContent(now); 322 setNodeChanged(true); 323 break; 324 } 325 } 326 } 327 328 getTimestamp()329 private static String getTimestamp() { // eg., 2006-04-10T20:40:08Z 330 return DateUtils.format(new Date(), DateUtils.ISO8601_DATETIME_PATTERN) + "Z"; //$NON-NLS-1$ 331 } 332 isNullString(String str)333 private static boolean isNullString(String str) 334 { 335 return RSSFeedUtil.isNullString(str); 336 } 337 338 }