Home | History | Annotate | Download | only in rss
      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
     81   public void setDebug(int debug) { this.debug = debug; }
     82 
     83   //required fields
     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   }
     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
     98   public void setReplacement(String replacement) { this.replacement = replacement; }
     99 
    100   // The method executing the task
    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
    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
    169   public Node getFoundNode()
    170   {
    171     return this.foundNode;
    172   }
    173   private void setFoundNode(Node foundNode)
    174   {
    175     this.foundNode = foundNode;
    176   }
    177 
    178   // has the desired node been found?
    179   public boolean getNodeFound()
    180   {
    181     return this.isNodeFound;
    182   }
    183   private void setNodeFound(boolean isNodeFound)
    184   {
    185     this.isNodeFound = isNodeFound;
    186   }
    187 
    188   // has the desired node been changed?
    189   public boolean getNodeChanged()
    190   {
    191     return this.isNodeChanged;
    192   }
    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    */
    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 
    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 
    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
    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 
    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 
    333   private static boolean isNullString(String str)
    334   {
    335     return RSSFeedUtil.isNullString(str);
    336   }
    337 
    338 }