Advertisement
Guest User

HttpBugzillaSession

a guest
Jan 30th, 2013
203
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 33.14 KB | None | 0 0
  1. /*
  2.  * This file is part of Bugzilla for Java.
  3.  *
  4.  *  Bugzilla for Java is free software: you can redistribute it
  5.  *  and/or modify it under the terms of version 3 of the GNU
  6.  *  Lesser General Public  License as published by the Free Software
  7.  *  Foundation.
  8.  *  
  9.  *  Bugzilla for Java is distributed in the hope that it will be useful,
  10.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *  GNU Lesser General Public License for more details.
  13.  *
  14.  *  You should have received a copy of the GNU Lesser General Public
  15.  *  License along with Bugzilla for Java.  If not, see
  16.  *  <http://www.gnu.org/licenses/lgpl-3.0.html>.
  17.  */
  18. package b4j.core.session;
  19.  
  20. import java.io.BufferedReader;
  21. import java.io.IOException;
  22. import java.io.InputStream;
  23. import java.io.InputStreamReader;
  24. import java.io.PrintWriter;
  25. import java.io.StringReader;
  26. import java.io.StringWriter;
  27. import java.net.HttpURLConnection;
  28. import java.text.ParseException;
  29. import java.util.ArrayList;
  30. import java.util.Iterator;
  31. import java.util.List;
  32. import java.util.regex.Matcher;
  33. import java.util.regex.Pattern;
  34.  
  35. import javax.xml.parsers.ParserConfigurationException;
  36. import javax.xml.parsers.SAXParser;
  37. import javax.xml.parsers.SAXParserFactory;
  38.  
  39. import org.apache.commons.io.IOUtils;
  40. import org.xml.sax.Attributes;
  41. import org.xml.sax.InputSource;
  42. import org.xml.sax.SAXException;
  43. import org.xml.sax.XMLReader;
  44. import org.xml.sax.ext.DefaultHandler2;
  45.  
  46. import b4j.core.Attachment;
  47. import b4j.core.Issue;
  48. import b4j.core.LongDescription;
  49. import b4j.core.SearchData;
  50. import b4j.core.SearchResultCountCallback;
  51. import b4j.util.BugzillaUtils;
  52. import b4j.util.UrlParameters;
  53.  
  54. /**
  55.  * Implements Bugzilla access via HTTP. Use this session object when you cannot
  56.  * access Bugzilla directly per JDBC. This implementation does not implement
  57.  * access via proxy yet.
  58.  *
  59.  * @author Ralph Schuster
  60.  *
  61.  */
  62. public class HttpBugzillaSession extends AbstractHttpSession {
  63.  
  64.     /** Constant for requesting URL connection to login page */
  65.     public static final int BUGZILLA_LOGIN = 0;
  66.     /** Constant for requesting URL connection to search result page */
  67.     public static final int BUGZILLA_SEARCH = 1;
  68.     /** Constant for requesting URL connection to logout page */
  69.     public static final int BUGZILLA_LOGOUT = 2;
  70.     /** Constant for requesting URL connection to show bug page */
  71.     public static final int BUGZILLA_SHOW_BUG = 3;
  72.     /** Constant for requesting URL connection to get attachment content */
  73.     public static final int BUGZILLA_GET_ATTACHMENT = 4;
  74.  
  75.     private static final String MINIMUM_BUGZILLA_VERSION = "2.20";
  76.     private static final String MAXIMUM_BUGZILLA_VERSION = null;
  77.  
  78.     /** The URL paths to the Bugzilla pages */
  79.     protected static final String[] PAGES = new String[] { "/index.cgi",
  80.             "/buglist.cgi", "/relogin.cgi", "/show_bug.cgi", "/attachment.cgi" };
  81.     private static UrlParameters DEFAULT_SEARCH_PARAMETERS;
  82.  
  83.     /**
  84.      * Default constructor.
  85.      */
  86.     public HttpBugzillaSession() {
  87.     }
  88.  
  89.     /**
  90.      * Returns the minimum Bugzilla version this session class supports.
  91.      *
  92.      * @see #MINIMUM_BUGZILLA_VERSION
  93.      * @return minimum version of supported Bugzilla software.
  94.      */
  95.     @Override
  96.     public String getMinimumBugzillaVersion() {
  97.         return MINIMUM_BUGZILLA_VERSION;
  98.     }
  99.  
  100.     /**
  101.      * Returns the maximum Bugzilla version this session class supports.
  102.      *
  103.      * @see #MAXIMUM_BUGZILLA_VERSION
  104.      * @return maximum version of supported Bugzilla software.
  105.      */
  106.     @Override
  107.     public String getMaximumBugzillaVersion() {
  108.         return MAXIMUM_BUGZILLA_VERSION;
  109.     }
  110.  
  111.     /**
  112.      * Opens the session with configured Bugzilla instance.
  113.      *
  114.      * @return true when session could be established successfully, false
  115.      *         otherwise
  116.      */
  117.     @Override
  118.     public boolean open() {
  119.         if (isLoggedIn())
  120.             return true;
  121.         setBugzillaVersion(null);
  122.  
  123.         // Exception: No login required
  124.         if (getLogin() == null) {
  125.             getLog().debug("No Auth required");
  126.             setLoggedIn(true);
  127.             return true;
  128.         }
  129.  
  130.         try {
  131.             // Bugzilla_login = xxx
  132.             // Bugzilla_password = xxx
  133.             // GoAheadAndLogIn = Login
  134.             UrlParameters params = new UrlParameters();
  135.             params.setParameter("Bugzilla_login", getLogin());
  136.             params.setParameter("Bugzilla_password", getPassword());
  137.             params.setParameter("GoAheadAndLogIn", "Login");
  138.             String paramString = params.getUrlEncodedString();
  139.  
  140.             // make a connection
  141.             HttpURLConnection con = getConnection(BUGZILLA_LOGIN);
  142.             con.setRequestMethod("POST");
  143.             con.setRequestProperty("Content-type",
  144.                     "application/x-www-form-urlencoded");
  145.             con.setRequestProperty("Content-Length", "" + paramString.length());
  146.             con.setDoOutput(true);
  147.             PrintWriter out = new PrintWriter(con.getOutputStream());
  148.             out.print(paramString);
  149.             out.flush();
  150.             out.close();
  151.  
  152.             // Read the response;
  153.             if (con.getResponseCode() == 200) {
  154.                 // debugResponse(con);
  155.                 boolean rc = retrieveCookies(con);
  156.  
  157.                 // Get Bugzilla version and test for compatibility
  158.                 BufferedReader r = new BufferedReader(new InputStreamReader(
  159.                         con.getInputStream()));
  160.                 Pattern p = Pattern.compile(".*version\\s+([\\d\\.]+).*",
  161.                         Pattern.CASE_INSENSITIVE);
  162.  
  163.                 String line;
  164.                 while ((line = r.readLine()) != null) {
  165.                     // Search for: version 3.0.5
  166.                     Matcher m = p.matcher(line);
  167.                     if (m.matches()) {
  168.                         setBugzillaVersion(m.group(1));
  169.                         break;
  170.                     }
  171.                 }
  172.  
  173.                 setLoggedIn(rc);
  174.                 if (getLog().isInfoEnabled()) {
  175.                     if (rc) {
  176.                         getLog().info("Session opened:   " + getBaseUrl());
  177.                         if (getLog().isDebugEnabled())
  178.                             getLog().debug(
  179.                                     "Bugzilla-Version: " + getBugzillaVersion());
  180.                     } else
  181.                         getLog().info("Bugzilla did not sent Cookie");
  182.                 }
  183.  
  184.                 if (rc)
  185.                     checkBugzillaVersion();
  186.  
  187.                 return rc;
  188.             } else {
  189.                 getLog().error(
  190.                         "Cannot open session: Response was \""
  191.                                 + con.getResponseMessage() + "\"");
  192.             }
  193.         } catch (IOException e) {
  194.             getLog().error("Cannot open session:", e);
  195.         }
  196.         return false;
  197.     }
  198.  
  199.     /**
  200.      * Closes the previously established Bugzilla session.
  201.      */
  202.     @Override
  203.     public void close() {
  204.         if (!isLoggedIn())
  205.             return;
  206.  
  207.         // Only when login was required
  208.         if (getLogin() != null) {
  209.             try {
  210.                 // make a connection
  211.                 HttpURLConnection con = getConnection(BUGZILLA_LOGOUT);
  212.                 con.getResponseCode();
  213.             } catch (IOException e) {
  214.  
  215.             }
  216.         }
  217.         super.close();
  218.     }
  219.  
  220.     /**
  221.      * {@inheritDoc}
  222.      */
  223.     @Override
  224.     public Issue getIssue(String id) {
  225.         List<String> idList = new ArrayList<String>();
  226.         idList.add(id);
  227.         BugzillaBugIterator i = new BugzillaBugIterator(idList);
  228.         if ((i != null) && i.hasNext())
  229.             return i.next();
  230.         return null;
  231.     }
  232.  
  233.     /**
  234.      * {@inheritDoc}
  235.      */
  236.     @Override
  237.     public InputStream getAttachment(Attachment attachment) throws IOException {
  238.         HttpURLConnection con = getConnection(BUGZILLA_GET_ATTACHMENT, "id="
  239.                 + attachment.getId());
  240.         return con.getInputStream();
  241.     }
  242.  
  243.     /**
  244.      * Performs a search for Bugzilla bugs. This method returns an iterator over
  245.      * all bug records found. The returned iterator will query its data when the
  246.      * first call to its {@link Iterator#next()} method is made. A separate
  247.      * thread will then be spawned to retrieve the required details.
  248.      *
  249.      * @param searchData
  250.      *            - all search parameters
  251.      * @param callback
  252.      *            - a callback object that will retrieve the number of bugs
  253.      *            found for this search
  254.      * @return iterator on all bugs fulfilling the criteria expressed by search
  255.      *         parameters.
  256.      */
  257.     @Override
  258.     public Iterator<Issue> searchBugs(SearchData searchData,
  259.             SearchResultCountCallback callback) {
  260.         if (!isLoggedIn())
  261.             return null;
  262.  
  263.         // Perform the search
  264.         try {
  265.             UrlParameters params = UrlParameters
  266.                     .createUrlParameters(searchData);
  267.             params.addDefaultParameters(getDefaultSearchParameters());
  268.             String paramString = params.getUrlEncodedString();
  269.  
  270.             // make a connection
  271.             HttpURLConnection con = getConnection(BUGZILLA_SEARCH, paramString);
  272.  
  273.             // Read the response;
  274.             if (con.getResponseCode() == 200) {
  275.                 // debugResponse(con);
  276.                 // if (true) return null;
  277.  
  278.                 List<String> idList = new ArrayList<String>();
  279.  
  280.                 // Parse the data for all bugs found
  281.                 BufferedReader r = new BufferedReader(new InputStreamReader(
  282.                         con.getInputStream()));
  283.                 Pattern p = Pattern
  284.                         .compile(".*href=\"show_bug\\.cgi\\?id=(\\d+)\">\\d+</a>.*");
  285.  
  286.                 String line;
  287.                 while ((line = r.readLine()) != null) {
  288.                     // Search for: <a href="show_bug.cgi?id=2349">2349</a>
  289.                     Matcher m = p.matcher(line);
  290.                     if (m.matches()) {
  291.                         idList.add(m.group(1));
  292.                     } // else if (line.indexOf("show_bug.cgi") >= 0)
  293.                         // log.info(line);
  294.                 }
  295.                 if (callback != null)
  296.                     callback.setResultCount(idList.size());
  297.                 if (getLog().isDebugEnabled())
  298.                     getLog().debug("Found " + idList.size() + " bugs");
  299.  
  300.                 // Return the bug iterator
  301.                 return new BugzillaBugIterator(idList);
  302.             } else {
  303.                 getLog().debug("Response invalid: " + con.getResponseCode());
  304.             }
  305.         } catch (IOException e) {
  306.             getLog().error("Cannot perform search", e);
  307.         }
  308.  
  309.         return null;
  310.     }
  311.  
  312.     /**
  313.      * Makes a request to Bugzilla without any GET parameters.
  314.      *
  315.      * @param bugzillaPage
  316.      *            - ID of page to make the request to.
  317.      * @return HTTP connection object
  318.      */
  319.     protected HttpURLConnection getConnection(int bugzillaPage) {
  320.         return getConnection(bugzillaPage, null);
  321.     }
  322.  
  323.     /**
  324.      * Makes a request to Bugzilla including eventual GET parameters. The method
  325.      * applies all cookies registered previously to allow a successful session
  326.      * connection.
  327.      *
  328.      * @param bugzillaPage
  329.      *            - ID of page to make the request to
  330.      * @return HTTP connection object
  331.      */
  332.     protected HttpURLConnection getConnection(int bugzillaPage, String getParams) {
  333.         return getConnection(getBaseUrl() + PAGES[bugzillaPage], getParams);
  334.     }
  335.  
  336.     /**
  337.      * Returns default search parameters. DO NOT modify these defaults!
  338.      *
  339.      * @return default search parameters.
  340.      */
  341.     public static UrlParameters getDefaultSearchParameters() {
  342.         if (DEFAULT_SEARCH_PARAMETERS == null) {
  343.             DEFAULT_SEARCH_PARAMETERS = new UrlParameters();
  344.             DEFAULT_SEARCH_PARAMETERS.setParameter("query_format", "advanced");
  345.             DEFAULT_SEARCH_PARAMETERS.setParameter("short_desc_type",
  346.                     "allwordssubstr");
  347.             // DEFAULT_SEARCH_PARAMETERS.setParameter("short_desc", "");
  348.             // DEFAULT_SEARCH_PARAMETERS.setParameter("classification", "");
  349.             // DEFAULT_SEARCH_PARAMETERS.setParameter("product", "");
  350.             // DEFAULT_SEARCH_PARAMETERS.setParameter("component", "");
  351.             // DEFAULT_SEARCH_PARAMETERS.setParameter("long_desc_type", "");
  352.             // DEFAULT_SEARCH_PARAMETERS.setParameter("long_desc", "");
  353.             DEFAULT_SEARCH_PARAMETERS.setParameter("bug_file_loc_type",
  354.                     "allwordssubstr");
  355.             // DEFAULT_SEARCH_PARAMETERS.setParameter("bug_file_loc", "");
  356.             DEFAULT_SEARCH_PARAMETERS.setParameter("keywords_type", "allwords");
  357.             // DEFAULT_SEARCH_PARAMETERS.setParameter("keywords", "");
  358.             // DEFAULT_SEARCH_PARAMETERS.setParameter("bug_status", "");
  359.             DEFAULT_SEARCH_PARAMETERS.setParameter("emailassigned_to1", "1");
  360.             DEFAULT_SEARCH_PARAMETERS.setParameter("emailtype1", "substring");
  361.             // DEFAULT_SEARCH_PARAMETERS.setParameter("email1", "");
  362.             DEFAULT_SEARCH_PARAMETERS.setParameter("emailassigned_to2", "1");
  363.             DEFAULT_SEARCH_PARAMETERS.setParameter("emailreporter2", "1");
  364.             DEFAULT_SEARCH_PARAMETERS.setParameter("emailqa_contact2", "1");
  365.             DEFAULT_SEARCH_PARAMETERS.setParameter("emailcc2", "1");
  366.             DEFAULT_SEARCH_PARAMETERS.setParameter("emailtype2", "substring");
  367.             // DEFAULT_SEARCH_PARAMETERS.setParameter("email2", "");
  368.             DEFAULT_SEARCH_PARAMETERS.setParameter("bugidtype", "include");
  369.             // DEFAULT_SEARCH_PARAMETERS.setParameter("bug_id", "");
  370.             // DEFAULT_SEARCH_PARAMETERS.setParameter("chfieldfrom", "");
  371.             DEFAULT_SEARCH_PARAMETERS.setParameter("chfieldto", "Now");
  372.             // DEFAULT_SEARCH_PARAMETERS.setParameter("chfieldvalue", "");
  373.             DEFAULT_SEARCH_PARAMETERS.setParameter("cmdtype", "doit");
  374.             DEFAULT_SEARCH_PARAMETERS.setParameter("order", "Bug Number");
  375.             DEFAULT_SEARCH_PARAMETERS.setParameter("field0-0-0", "noop");
  376.             DEFAULT_SEARCH_PARAMETERS.setParameter("type0-0-0", "noop");
  377.             // DEFAULT_SEARCH_PARAMETERS.setParameter("value0-0-0", "");
  378.         }
  379.         return DEFAULT_SEARCH_PARAMETERS;
  380.     }
  381.  
  382.     /**
  383.      * Implementation of a bug iterator. This implementation is based on
  384.      * Silberschatz' proposal for synchronizing a reader and a writer thread.
  385.      * The first call to {@link BugzillaBugIterator#next()} will spawn the
  386.      * writer thread that actually retrieves bug data from Bugzilla.
  387.      *
  388.      * @author Ralph Schuster
  389.      *
  390.      */
  391.     protected class BugzillaBugIterator implements Iterator<Issue> {
  392.  
  393.         private List<String> bugList;
  394.         private int delivered;
  395.         private List<Issue> availableBugs;
  396.         private XmlParser xmlParser;
  397.  
  398.         /**
  399.          * Default constructor.
  400.          *
  401.          * @param bugList
  402.          *            - bug ID list to retrieve
  403.          */
  404.         public BugzillaBugIterator(List<String> bugList) {
  405.             delivered = 0;
  406.             this.bugList = bugList;
  407.             availableBugs = new ArrayList<Issue>();
  408.         }
  409.  
  410.         /**
  411.          * Returns true while number of delivered bugs (calls to {@link #next()}
  412.          * are less than number of bugs in request list.
  413.          *
  414.          * @return true if there are still bugs in the queue to read.
  415.          */
  416.         @Override
  417.         public boolean hasNext() {
  418.             return delivered < bugList.size();
  419.         }
  420.  
  421.         /**
  422.          * Delivers the next bug. The first call will trigger spawning of the
  423.          * writer thread. This implementation is based on Silberschatz'
  424.          * synchronization solution for reader and writer threads (reader's part
  425.          * here). That means, the call will wait until the next bug is available
  426.          * if required.
  427.          *
  428.          * @return next bug in queue
  429.          */
  430.         @Override
  431.         public synchronized Issue next() {
  432.             Issue rc;
  433.             if (xmlParser == null)
  434.                 startXmlParser();
  435.             if (delivered >= bugList.size())
  436.                 throw new IllegalStateException("Empty queue");
  437.  
  438.             while (availableBugs.isEmpty()) {
  439.                 try {
  440.                     wait();
  441.                 } catch (InterruptedException e) {
  442.                 }
  443.             }
  444.             rc = availableBugs.remove(0);
  445.             delivered++;
  446.  
  447.             notify();
  448.  
  449.             return rc;
  450.         }
  451.  
  452.         /**
  453.          * Adds a new bug to the list of available bugs. This implementation is
  454.          * based on Silberschatz' synchronization solution for reader and writer
  455.          * threads (writer's part here).
  456.          *
  457.          * @param bug
  458.          *            - bug to add to queue
  459.          */
  460.         protected synchronized void addBug(Issue bug) {
  461.             while (availableBugs.size() >= 20) {
  462.                 try {
  463.                     wait();
  464.                 } catch (InterruptedException e) {
  465.                 }
  466.             }
  467.             availableBugs.add(bug);
  468.  
  469.             notify();
  470.         }
  471.  
  472.         /**
  473.          * Always throws an exception.
  474.          */
  475.         @Override
  476.         public void remove() {
  477.             throw new UnsupportedOperationException(
  478.                     "This is a read-only iterator");
  479.         }
  480.  
  481.         /**
  482.          * Starts the writer's thread. This method will create the appropriate
  483.          * POST request to the Bugzilla instance and hand over the connection to
  484.          * the new thread. Internal variables are set to indicate that the
  485.          * writer thread is running.
  486.          */
  487.         protected void startXmlParser() {
  488.             try {
  489.                 if (getLog().isTraceEnabled())
  490.                     getLog().trace("Requesting XML file...");
  491.  
  492.                 // Build parameters
  493.                 UrlParameters parameters = new UrlParameters();
  494.                 parameters.addAll("id", bugList);
  495.                 parameters.setParameter("ctype", "xml");
  496.                 parameters.setParameter("excludefield", "attachmentdata");
  497.                 parameters.setParameter("submit", "XML");
  498.                 String paramString = parameters.getUrlEncodedString();
  499.  
  500.                 // make a connection
  501.                 HttpURLConnection con = getConnection(BUGZILLA_SHOW_BUG);
  502.                 con.setRequestMethod("POST");
  503.                 con.setRequestProperty("Content-type",
  504.                         "application/x-www-form-urlencoded");
  505.                 con.setRequestProperty("Content-Length",
  506.                         "" + paramString.length());
  507.                 con.setDoOutput(true);
  508.                 PrintWriter out = new PrintWriter(con.getOutputStream());
  509.                 out.print(paramString);
  510.                 out.flush();
  511.                 out.close();
  512.  
  513.                 if (getLog().isTraceEnabled())
  514.                     getLog().trace("Awaiting XML file...");
  515.                 // Read the response
  516.                 if (con.getResponseCode() == 200) {
  517.                     if (getLog().isTraceEnabled())
  518.                         getLog().trace("Receiving XML file...");
  519.                     xmlParser = new XmlParser(con.getInputStream(), this);
  520.                     Thread t = new Thread(xmlParser);
  521.                     t.start();
  522.                 }
  523.             } catch (IOException e) {
  524.  
  525.             }
  526.         }
  527.     }
  528.  
  529.     /**
  530.      * Does the actual meat by parsing the XML response. Implementation of the
  531.      * separate writer thread. The XML will be parsed (SAX implementation) and
  532.      * all found bugs will be added to the corresponding iterator object (
  533.      * {@link BugzillaBugIterator#addBug(Issue)}).
  534.      *
  535.      * @author Ralph Schuster
  536.      */
  537.     protected class XmlParser extends DefaultHandler2 implements Runnable {
  538.  
  539.         private InputStream xmlStream;
  540.         private BugzillaBugIterator iterator;
  541.         private XMLReader xmlReader;
  542.         private Issue currentBug;
  543.         private LongDescription currentLongDescription;
  544.         private Attachment currentAttachment;
  545.         private StringBuffer currentContent;
  546.         private String currentCustomField;
  547.         private String bugzillaVersion;
  548.         private String bugzillaUri;
  549.  
  550.         /**
  551.          * Constructor.
  552.          *
  553.          * @param xmlStream
  554.          *            - input stream with XML response from Bugzilla
  555.          * @param iterator
  556.          *            - corresponding iterator that receives the results
  557.          */
  558.         public XmlParser(InputStream xmlStream, BugzillaBugIterator iterator) {
  559.             this.xmlStream = xmlStream;
  560.             this.iterator = iterator;
  561.         }
  562.  
  563.         /**
  564.          * Runs the extraction.
  565.          */
  566.         public void run() {
  567.             try {
  568.                 SAXParserFactory factory = SAXParserFactory.newInstance();
  569.                 // Prevent fetching the DTD
  570.                 factory.setValidating(false);
  571.                 factory.setFeature(
  572.                         "http://apache.org/xml/features/nonvalidating/load-external-dtd",
  573.                         false);
  574.  
  575.                 // Create the XMLReader
  576.                 SAXParser xmlParser = factory.newSAXParser();
  577.                 xmlReader = xmlParser.getXMLReader();
  578.  
  579.                 // This class itself will take care of the elements
  580.                 xmlReader.setContentHandler(this);
  581.  
  582.                 StringWriter writer = new StringWriter();
  583.                 IOUtils.copy(xmlStream, writer, "UTF-8");
  584.                 String xmlString = writer.toString();
  585.                 String escapedXML = stripNonValidXMLCharacters(xmlString);
  586.  
  587.                 xmlReader.parse(new InputSource(new StringReader(escapedXML)));
  588.                 if (getLog().isTraceEnabled())
  589.                     getLog().trace("XML file completed");
  590.             } catch (IOException e) {
  591.                 getLog().error("Error while retrieving Bugzilla XML response:",
  592.                         e);
  593.             } catch (ParserConfigurationException e) {
  594.                 getLog().error("SAXParser not configured:", e);
  595.             } catch (SAXException e) {
  596.                 if (e.getMessage().indexOf("invalid XML character") >= 0) {
  597.                     getLog().error(
  598.                             "The XML file received contains illegal characters. This is not a B4J error but a Bugzilla problem. Sorry",
  599.                             e);
  600.                 } else {
  601.                     getLog().error(
  602.                             "Error while parsing Bugzilla XML response:", e);
  603.                 }
  604.             }
  605.         }
  606.  
  607.         /**
  608.          * This method cleans all the invalid characters in the XML and makes it
  609.          * conform to XML 1.0 standard
  610.          *
  611.          * @param in
  612.          *            The XML as String whose in-valid characters we want to
  613.          *            remove.
  614.          * @return The XML as String, stripped of all invalid characters
  615.          */
  616.         private String stripNonValidXMLCharacters(String in) {
  617.             StringBuffer out = new StringBuffer(); // Used to hold the output.
  618.             char current; // Used to reference the current character.
  619.  
  620.             if (in == null || ("".equals(in)))
  621.                 return ""; // vacancy test.
  622.             for (int i = 0; i < in.length(); i++) {
  623.                 current = in.charAt(i); // NOTE: No IndexOutOfBoundsException
  624.                                         // caught here; it should not happen.
  625.                 if ((current == 0x9) || (current == 0xA) || (current == 0xD)
  626.                         || ((current >= 0x20) && (current <= 0xD7FF))
  627.                         || ((current >= 0xE000) && (current <= 0xFFFD))
  628.                         || ((current >= 0x10000) && (current <= 0x10FFFF)))
  629.                     out.append(current);
  630.             }
  631.             return out.toString();
  632.         }
  633.  
  634.         /**
  635.          * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String,
  636.          *      java.lang.String, java.lang.String, org.xml.sax.Attributes)
  637.          */
  638.         @Override
  639.         public void startElement(String uri, String localName, String name,
  640.                 Attributes attributes) throws SAXException {
  641.             super.startElement(uri, localName, name, attributes);
  642.             if (name.equals("bugzilla")) {
  643.                 bugzillaUri = attributes.getValue("urlbase");
  644.                 bugzillaVersion = attributes.getValue("version");
  645.                 setBugzillaVersion(bugzillaVersion);
  646.             } else if (name.equals("bug")) {
  647.                 currentBug = createIssue();
  648.                 currentBug.setBugzillaUri(bugzillaUri);
  649.                 currentBug.setBugzillaVersion(bugzillaVersion);
  650.             } else if (name.equals("bug_id")) {
  651.                 currentContent = new StringBuffer();
  652.             } else if (name.equals("creation_ts")) { // 2008-07-23 12:28
  653.                 currentContent = new StringBuffer();
  654.             } else if (name.equals("short_desc")) {
  655.                 currentContent = new StringBuffer();
  656.             } else if (name.equals("delta_ts")) { // 2008-07-23 12:28:22
  657.                 currentContent = new StringBuffer();
  658.             } else if (name.equals("reporter_accessible")) {
  659.                 currentContent = new StringBuffer();
  660.             } else if (name.equals("cclist_accessible")) {
  661.                 currentContent = new StringBuffer();
  662.             } else if (name.equals("classification_id")) {
  663.                 currentContent = new StringBuffer();
  664.             } else if (name.equals("classification")) {
  665.                 currentContent = new StringBuffer();
  666.             } else if (name.equals("product")) {
  667.                 currentContent = new StringBuffer();
  668.             } else if (name.equals("component")) {
  669.                 currentContent = new StringBuffer();
  670.             } else if (name.equals("version")) {
  671.                 currentContent = new StringBuffer();
  672.             } else if (name.equals("rep_platform")) {
  673.                 currentContent = new StringBuffer();
  674.             } else if (name.equals("op_sys")) {
  675.                 currentContent = new StringBuffer();
  676.             } else if (name.equals("bug_status")) {
  677.                 currentContent = new StringBuffer();
  678.             } else if (name.equals("resolution")) {
  679.                 currentContent = new StringBuffer();
  680.             } else if (name.equals("priority")) {
  681.                 currentContent = new StringBuffer();
  682.             } else if (name.equals("bug_severity")) {
  683.                 currentContent = new StringBuffer();
  684.             } else if (name.equals("target_milestone")) {
  685.                 currentContent = new StringBuffer();
  686.             } else if (name.equals("everconfirmed")) {
  687.                 currentContent = new StringBuffer();
  688.             } else if (name.equals("reporter")) {
  689.                 currentContent = new StringBuffer();
  690.             } else if (name.equals("assigned_to")) {
  691.                 currentContent = new StringBuffer();
  692.             } else if (name.equals("qa_contact")) {
  693.                 currentContent = new StringBuffer();
  694.             } else if (name.equals("long_desc")) { // multiple
  695.                 currentLongDescription = currentBug.addLongDescription();
  696.             } else if (name.equals("commentid")) {
  697.                 currentContent = new StringBuffer();
  698.             } else if (name.equals("who")) {
  699.                 currentContent = new StringBuffer();
  700.             } else if (name.equals("bug_when")) { // 2008-07-23 12:28:22
  701.                 currentContent = new StringBuffer();
  702.             } else if (name.equals("thetext")) {
  703.                 currentContent = new StringBuffer();
  704.             } else if (name.equals("bug_file_loc")) {
  705.                 currentContent = new StringBuffer();
  706.             } else if (name.equals("cc")) { // multiple
  707.                 currentContent = new StringBuffer();
  708.             } else if (name.equals("attachment")) { // multiple
  709.                 currentAttachment = currentBug.addAttachment();
  710.             } else if (name.equals("attachid")) {
  711.                 currentContent = new StringBuffer();
  712.             } else if (name.equals("date")) {
  713.                 currentContent = new StringBuffer();
  714.             } else if (name.equals("desc")) {
  715.                 currentContent = new StringBuffer();
  716.             } else if (name.equals("filename")) {
  717.                 currentContent = new StringBuffer();
  718.             } else if (name.equals("type")) {
  719.                 currentContent = new StringBuffer();
  720.             } else if (name.equals("blocked")) {
  721.                 currentContent = new StringBuffer();
  722.             } else if (name.equals("alias")) {
  723.                 currentContent = new StringBuffer();
  724.             } else if (name.equals("status_whiteboard")) {
  725.                 currentContent = new StringBuffer();
  726.             } else if (name.equals("estimated_time")) {
  727.                 currentContent = new StringBuffer();
  728.             } else if (name.equals("remaining_time")) {
  729.                 currentContent = new StringBuffer();
  730.             } else if (name.equals("actual_time")) {
  731.                 currentContent = new StringBuffer();
  732.             } else if (name.equals("deadline")) {
  733.                 currentContent = new StringBuffer();
  734.             } else {
  735.                 currentCustomField = name;
  736.                 currentContent = new StringBuffer();
  737.                 // log.warn("Custom field: "+name);
  738.             }
  739.         }
  740.  
  741.         /**
  742.          * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String,
  743.          *      java.lang.String, java.lang.String)
  744.          */
  745.         @Override
  746.         public void endElement(String uri, String localName, String name)
  747.                 throws SAXException {
  748.             if (name.equals("bug")) {
  749.                 iterator.addBug(currentBug);
  750.                 currentBug = null;
  751.             } else if (name.equals("bug_id")) {
  752.                 currentBug.setId(currentContent.toString());
  753.                 currentContent = null;
  754.             } else if (name.equals("creation_ts")) { // 2008-07-23 12:28
  755.                 try {
  756.                     currentBug.setCreationTimestamp(BugzillaUtils
  757.                             .parseDate(currentContent.toString()));
  758.                 } catch (ParseException e) {
  759.                     getLog().error(
  760.                             "Cannot parse this time: "
  761.                                     + currentContent.toString());
  762.                 }
  763.                 currentContent = null;
  764.             } else if (name.equals("short_desc")) {
  765.                 currentBug.setShortDescription(currentContent.toString());
  766.                 currentContent = null;
  767.             } else if (name.equals("delta_ts")) { // 2008-07-23 12:28:22
  768.                 try {
  769.                     currentBug.setDeltaTimestamp(BugzillaUtils
  770.                             .parseDate(currentContent.toString()));
  771.                 } catch (ParseException e) {
  772.                     getLog().error(
  773.                             "Cannot parse this time: "
  774.                                     + currentContent.toString());
  775.                 }
  776.                 currentContent = null;
  777.             } else if (name.equals("reporter_accessible")) {
  778.                 currentBug.setReporterAccessible(parseBoolean(currentContent
  779.                         .toString()));
  780.                 currentContent = null;
  781.             } else if (name.equals("cclist_accessible")) {
  782.                 currentBug.setCclistAccessible(parseBoolean(currentContent
  783.                         .toString()));
  784.                 currentContent = null;
  785.             } else if (name.equals("classification_id")) {
  786.                 currentBug.setType(Long.parseLong(currentContent.toString()));
  787.                 currentContent = null;
  788.             } else if (name.equals("classification")) {
  789.                 currentBug.setTypeName(currentContent.toString());
  790.                 currentContent = null;
  791.             } else if (name.equals("product")) {
  792.                 currentBug.setProduct(currentContent.toString());
  793.                 currentContent = null;
  794.             } else if (name.equals("component")) {
  795.                 currentBug.setComponent(currentContent.toString());
  796.                 currentContent = null;
  797.             } else if (name.equals("version")) {
  798.                 currentBug.setVersion(currentContent.toString());
  799.                 currentContent = null;
  800.             } else if (name.equals("rep_platform")) {
  801.                 currentBug.setRepPlatform(currentContent.toString());
  802.                 currentContent = null;
  803.             } else if (name.equals("op_sys")) {
  804.                 currentBug.setOpSys(currentContent.toString());
  805.                 currentContent = null;
  806.             } else if (name.equals("bug_status")) {
  807.                 currentBug.setStatus(currentContent.toString());
  808.                 currentContent = null;
  809.             } else if (name.equals("resolution")) {
  810.                 currentBug.setResolution(currentContent.toString());
  811.                 currentContent = null;
  812.             } else if (name.equals("priority")) {
  813.                 currentBug.setPriority(currentContent.toString());
  814.                 currentContent = null;
  815.             } else if (name.equals("bug_severity")) {
  816.                 currentBug.setSeverity(currentContent.toString());
  817.                 currentContent = null;
  818.             } else if (name.equals("target_milestone")) {
  819.                 currentBug.setTargetMilestone(currentContent.toString());
  820.                 currentContent = null;
  821.             } else if (name.equals("everconfirmed")) {
  822.                 currentBug.setEverConfirmed(parseBoolean(currentContent
  823.                         .toString()));
  824.                 currentContent = null;
  825.             } else if (name.equals("reporter")) {
  826.                 currentBug.setReporter(currentContent.toString());
  827.                 currentContent = null;
  828.             } else if (name.equals("assigned_to")) {
  829.                 currentBug.setAssignee(currentContent.toString());
  830.                 currentContent = null;
  831.             } else if (name.equals("qa_contact")) {
  832.                 currentBug.setQaContact(currentContent.toString());
  833.                 currentContent = null;
  834.             } else if (name.equals("long_desc")) { // multiple
  835.                 currentLongDescription = null;
  836.             } else if (name.equals("commentid")) {
  837.                 currentLongDescription.setId(currentContent.toString());
  838.             } else if (name.equals("who")) {
  839.                 currentLongDescription.setWho(currentContent.toString());
  840.                 currentContent = null;
  841.             } else if (name.equals("bug_when")) { // 2008-07-23 12:28:22
  842.                 try {
  843.                     currentLongDescription.setWhen(BugzillaUtils
  844.                             .parseDate(currentContent.toString()));
  845.                 } catch (ParseException e) {
  846.                     getLog().error(
  847.                             "Cannot parse this time: "
  848.                                     + currentContent.toString());
  849.                 }
  850.                 currentContent = null;
  851.             } else if (name.equals("thetext")) {
  852.                 currentLongDescription.setTheText(currentContent.toString());
  853.                 currentContent = null;
  854.             } else if (name.equals("bug_file_loc")) {
  855.                 currentBug.setFileLocation(currentContent.toString());
  856.                 currentContent = null;
  857.             } else if (name.equals("attachment")) { // multiple
  858.                 currentAttachment = null;
  859.             } else if (name.equals("attachid")) {
  860.                 if (currentAttachment != null) {
  861.                     currentAttachment.setId(Long.parseLong(currentContent
  862.                             .toString()));
  863.                 } else if (currentLongDescription != null) {
  864.                     currentLongDescription.addAttachment(Long
  865.                             .parseLong(currentContent.toString()));
  866.                 }
  867.                 currentContent = null;
  868.             } else if (name.equals("date")) {
  869.                 currentContent = null;
  870.             } else if (name.equals("desc")) {
  871.                 currentAttachment.setDescription(currentContent.toString());
  872.                 currentContent = null;
  873.             } else if (name.equals("filename")) {
  874.                 currentAttachment.setFilename(currentContent.toString());
  875.                 currentContent = null;
  876.             } else if (name.equals("type")) {
  877.                 currentAttachment.setType(currentContent.toString());
  878.                 currentContent = null;
  879.             } else if (name.equals("cc")) { // multiple
  880.                 currentBug.addCc(currentContent.toString());
  881.                 currentContent = null;
  882.             } else if (name.equals("blocked")) {
  883.                 currentBug
  884.                         .setBlocked(Long.parseLong(currentContent.toString()));
  885.                 currentContent = null;
  886.             } else if (name.equals("alias")) {
  887.                 currentBug.setAlias(currentContent.toString());
  888.                 currentContent = null;
  889.             } else if (name.equals("status_whiteboard")) {
  890.                 currentBug.setWhiteboard(currentContent.toString());
  891.                 currentContent = null;
  892.             } else if (name.equals("estimated_time")) {
  893.                 currentBug.setEstimatedTime(Double.parseDouble(currentContent
  894.                         .toString()));
  895.                 currentContent = null;
  896.             } else if (name.equals("remaining_time")) {
  897.                 currentBug.setRemainingTime(Double.parseDouble(currentContent
  898.                         .toString()));
  899.                 currentContent = null;
  900.             } else if (name.equals("actual_time")) {
  901.                 currentBug.setActualTime(Double.parseDouble(currentContent
  902.                         .toString()));
  903.                 currentContent = null;
  904.             } else if (name.equals("deadline")) {
  905.                 try {
  906.                     currentBug.setDeadline(BugzillaUtils
  907.                             .parseDate(currentContent.toString()));
  908.                 } catch (ParseException e) {
  909.                     getLog().error(
  910.                             "Cannot parse this date: "
  911.                                     + currentContent.toString());
  912.                 }
  913.                 currentContent = null;
  914.             } else {
  915.                 if ((currentCustomField != null) && (currentContent != null)) {
  916.                     if (currentBug != null) {
  917.                         currentBug.setCustomField(currentCustomField,
  918.                                 currentContent.toString());
  919.                         currentCustomField = null;
  920.                         currentContent = null;
  921.                     }
  922.                 }
  923.             }
  924.             super.endElement(uri, localName, name);
  925.         }
  926.  
  927.         /**
  928.          * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int)
  929.          */
  930.         @Override
  931.         public void characters(char[] ch, int start, int length)
  932.                 throws SAXException {
  933.             if (currentContent != null)
  934.                 currentContent.append(ch, start, length);
  935.             super.characters(ch, start, length);
  936.         }
  937.  
  938.         /**
  939.          * @see org.xml.sax.helpers.DefaultHandler#startDocument()
  940.          */
  941.         @Override
  942.         public void startDocument() throws SAXException {
  943.             // Nothing to do
  944.             super.startDocument();
  945.         }
  946.  
  947.         /**
  948.          * @see org.xml.sax.helpers.DefaultHandler#endDocument()
  949.          */
  950.         @Override
  951.         public void endDocument() throws SAXException {
  952.             // Nothing to do
  953.             super.endDocument();
  954.         }
  955.  
  956.         /**
  957.          * Parses a boolean for Bugzilla XML. Bugzilla uses "1" to represent a
  958.          * TRUE value in its XML.
  959.          *
  960.          * @param s
  961.          *            - boolean to parse
  962.          * @return true if string represented the TRUE value
  963.          */
  964.         public boolean parseBoolean(String s) {
  965.             if (s == null)
  966.                 return false;
  967.             s = s.trim();
  968.             if (s.length() == 0)
  969.                 return false;
  970.             if (s.equals("1"))
  971.                 return true;
  972.             if (s.equals("0"))
  973.                 return false;
  974.             return Boolean.parseBoolean(s);
  975.         }
  976.     }
  977. }
  978.  
  979. /*
  980.  *
  981.  * query_format=advanced short_desc_type=allwordssubstr short_desc=
  982.  * classification= product= long_desc_type=substring long_desc=
  983.  * bug_file_loc_type=allwordssubstr bug_file_loc= keywords_type=allwords
  984.  * keywords= bug_status= emailassigned_to1=1 emailtype1=substring email1=
  985.  * emailassigned_to2=1 emailreporter2=1 emailqa_contact2=1 emailcc2=1
  986.  * emailtype2=substring email2= bugidtype=include bug_id= chfieldfrom=
  987.  * chfieldto=Now chfieldvalue= cmdtype=doit order=Bug+Number field0-0-0=noop
  988.  * type0-0-0=noop value0-0-0=
  989.  */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement