de.suse.swamp.core.util.BugzillaTools.java Source code

Java tutorial

Introduction

Here is the source code for de.suse.swamp.core.util.BugzillaTools.java

Source

/*
 * SWAMP Workflow Administration and Management Platform
 *
 * Copyright (c) 2005 Thomas Schmidt <tschmidt [at] suse.de>
 * Copyright (c) 2006 Novell Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 * St, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * In addition, as a special exception, Novell Inc. gives permission to link the
 * code of this program with the following applications:
 *
 * - All applications of the Apache Software Foundation
 *
 * and distribute such linked combinations.
 */

package de.suse.swamp.core.util;

import java.io.*;
import java.text.*;
import java.util.*;

import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.auth.*;
import org.apache.commons.httpclient.methods.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

import de.suse.swamp.core.container.*;
import de.suse.swamp.core.data.*;
import de.suse.swamp.core.data.datatypes.*;
import de.suse.swamp.core.security.*;
import de.suse.swamp.util.*;

public class BugzillaTools {

    private String errormsg = null;
    private Hashtable bugData = null;
    private static Cookie[] cookies = null;
    private SWAMP swamp = SWAMP.getInstance();

    // extra logger for bugzilla stuff
    public static org.apache.log4j.Logger log = org.apache.log4j.Logger
            .getLogger("de.suse.swamp.core.util.BugzillaTools");

    // cache bug data with same excludefield parameters
    // key: bugid value: Hashtable with keys: excludefields, date, <bugdatafields>
    public static Hashtable bugzillaCache = new Hashtable();

    public BugzillaTools() {
    }

    public void fetchBugzillaInfo(Dataset dataset, int bugid) throws Exception {
        ArrayList excludeFields = new ArrayList();
        if (dataset != null && !dataset.containsDatabit("description")) {
            excludeFields.add("long_desc");
        }

        Hashtable bug = getBugData(bugid, excludeFields);
        // only store if a dataset is provided
        if (dataset != null) {
            for (Iterator it = dataset.getDatabits().iterator(); it.hasNext();) {
                Databit bit = (Databit) it.next();
                String bitName = bit.getName();
                if (bitName.equals("people")) {
                    if (bit.setValue(((SWAMPHashSet) bug.get("people")).toString(", "), SWAMPUser.SYSTEMUSERNAME)) {
                        Logger.LOG("Bugzilla copy: " + bitName + "=" + bug.get(bitName), log);
                    }
                } else if (bitName.equals("delta_time") && bug.containsKey("delta")) {
                    DateFormat df1 = new SimpleDateFormat(dateDatabit.dateFormat);
                    bit.setValue(df1.format((Date) bug.get("delta")), SWAMPUser.SYSTEMUSERNAME);
                } else if (bug.containsKey(bitName)) {
                    if (bit.setValue((String) bug.get(bitName), SWAMPUser.SYSTEMUSERNAME)) {
                        Logger.DEBUG("Bugzilla copy: " + bitName + "=" + bug.get(bitName), log);
                    }
                }
            }
        }
    }

    /**
     * This method will return a HashMap with key= name of bugzilla xml element
     * value = value of the elements CDDATA.
     * additional values are "people", a SWAMPHashSet of people contained in the bug
     * "delta": Date of the last action in the bug
     * "description": String - the first comment
     *
     * @param bugid
     * @return
     * @throws Exception
     */
    public Hashtable getBugData(int bugid, List excludeFields) throws Exception {

        /* Hashtable cacheBugData = getCacheEntry(bugid, excludeFields);
        if (cacheBugData != null) {
        Logger.LOG("Reading Bugzilla XML for bug #" + bugid + " from cache.", log);
        return cacheBugData;
        }
            
        String queryUrl = swamp.getProperty("BUGZILLA_QUERYURL") + bugid;
        queryUrl += "&excludefield=attachment";
        if (excludeFields != null && excludeFields.size() > 0){
        for (Iterator it = excludeFields.iterator(); it.hasNext(); ){
            queryUrl += "&excludefield=" + it.next();
        }
        }
        Logger.LOG("Reading Bugzilla XML for bug #" + bugid, log);
        try {
        xmlToData(queryUrl);
        if (bugData.get("assigned_to") == null) {
            Logger.ERROR("Bugzilla session not valid. Trying new login...");
            BugzillaTools.cookies = null;
            xmlToData(queryUrl);
        }
        } catch (Exception e) {
        if (e.getMessage().indexOf("NotPermitted") >= 0){
            Logger.ERROR("Bugzilla session not valid. Trying new login...");
            BugzillaTools.cookies = null;
            xmlToData(queryUrl);
        } else {
            throw e;
        }
        }
        bugData.put("excludefields", excludeFields);
        bugData.put("date", new Date());
        synchronized (bugzillaCache) {
        bugzillaCache.put(new Integer(bugid), bugData);
        }
        return bugData; */
        Hashtable h = new Hashtable();
        h.put("foo", "bar");
        return h;
    }

    public Hashtable getBugData(String bugid, List excludeFields) throws Exception {
        return getBugData(Integer.valueOf(bugid).intValue(), excludeFields);
    }

    private Cookie[] getCookies() throws Exception {
        if (cookies == null) {
            cookies = bzConnect(swamp.getProperty("BUGZILLA_USER"), swamp.getProperty("BUGZILLA_PASSWORD"));
        }
        return cookies;
    }

    private Cookie[] bzConnect(String username, String pwd) throws Exception {
        Logger.DEBUG("Performing bugzilla login...");
        HttpState initialState = new HttpState();
        // Do a Login at Bugzilla
        HttpClient httpclient = new HttpClient();
        httpclient.setState(initialState);

        String loginUrl = swamp.getProperty("BUGZILLA_LOGIN_URL");
        // add form fields for logging in:
        String usernameField = swamp.getProperty("BUGZILLA_LOGIN_FORM_USERNAME");
        String passwordField = swamp.getProperty("BUGZILLA_LOGIN_FORM_PWD");
        NameValuePair login = new NameValuePair(usernameField, username);
        NameValuePair pw = new NameValuePair(passwordField, pwd);
        NameValuePair loginid = new NameValuePair("GoAheadAndLogIn", "1");

        PostMethod httppost = new PostMethod(loginUrl);
        httppost.setRequestBody(new NameValuePair[] { login, pw, loginid });
        try {
            httpclient.executeMethod(httppost);
        } catch (Exception e) {
            throw new Exception("Could not connect to " + loginUrl + " (error: " + e.getMessage() + ")");
        }
        Cookie[] cookies = httpclient.getState().getCookies();
        //System.out.println("Response: " + httppost.getResponseBodyAsString());
        if (cookies == null || cookies.length == 0) {
            throw new Exception("Could not login to " + loginUrl);
        }
        httppost.releaseConnection();
        return cookies;
    }

    private synchronized void xmlToData(String url) throws Exception {

        HttpState initialState = new HttpState();

        String authUsername = swamp.getProperty("BUGZILLA_AUTH_USERNAME");
        String authPassword = swamp.getProperty("BUGZILLA_AUTH_PWD");

        if (authUsername != null && authUsername.length() != 0) {
            Credentials defaultcreds = new UsernamePasswordCredentials(authUsername, authPassword);
            initialState.setCredentials(AuthScope.ANY, defaultcreds);
        } else {
            Cookie[] cookies = getCookies();
            for (int i = 0; i < cookies.length; i++) {
                initialState.addCookie(cookies[i]);
                Logger.DEBUG("Added Cookie: " + cookies[i].getName() + "=" + cookies[i].getValue(), log);
            }
        }
        HttpClient httpclient = new HttpClient();
        httpclient.setState(initialState);
        HttpMethod httpget = new GetMethod(url);
        try {
            httpclient.executeMethod(httpget);
        } catch (Exception e) {
            throw new Exception("Could not get URL " + url);
        }

        String content = httpget.getResponseBodyAsString();
        char[] chars = content.toCharArray();

        // removing illegal characters from bugzilla output.
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] < 32 && chars[i] != 9 && chars[i] != 10 && chars[i] != 13) {
                Logger.DEBUG("Removing illegal character: '" + chars[i] + "' on position " + i, log);
                chars[i] = ' ';
            }
        }
        Logger.DEBUG(String.valueOf(chars), log);
        CharArrayReader reader = new CharArrayReader(chars);
        XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
        parser.setFeature("http://xml.org/sax/features/validation", false);
        // disable parsing of external dtd
        parser.setFeature("http://xml.org/sax/features/external-general-entities", false);
        parser.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
        parser.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
        // get XML File
        BugzillaReader handler = new BugzillaReader();
        parser.setContentHandler(handler);
        InputSource source = new InputSource();
        source.setCharacterStream(reader);
        source.setEncoding("utf-8");
        try {
            parser.parse(source);
        } catch (SAXParseException spe) {
            spe.printStackTrace();
            throw spe;
        }
        httpget.releaseConnection();
        if (errormsg != null) {
            throw new Exception(errormsg);
        }
    }

    private Hashtable getCacheEntry(int bugId, List excludefields) {
        synchronized (bugzillaCache) {
            cacheMaintenance();
            Hashtable cacheEntry = (Hashtable) bugzillaCache.get(new Integer(bugId));
            if (cacheEntry != null && (cacheEntry.get("excludefields").equals(excludefields)
                    || cacheEntry.get("excludefields") == null
                    || ((List) cacheEntry.get("excludefields")).size() == 0)) {
                return (Hashtable) bugzillaCache.get(new Integer(bugId));
            }
        }
        return null;
    }

    private void cacheMaintenance() {
        // do maintenance, remove outdated entries
        List removeIds = new ArrayList();
        synchronized (bugzillaCache) {
            for (Iterator it = bugzillaCache.keySet().iterator(); it.hasNext();) {
                Integer id = (Integer) it.next();
                Date date = (Date) ((Hashtable) bugzillaCache.get(id)).get("date");
                Date outDate = new Date(new Date().getTime() - 1000 * 60 * 20);
                if (date == null || date.before(outDate))
                    removeIds.add(id);
            }
            for (Iterator it = removeIds.iterator(); it.hasNext();) {
                Integer id = (Integer) it.next();
                bugzillaCache.remove(id);
                Logger.DEBUG("Bug cache outdated: " + id);
            }
        }
    }

    /*
     * make that an inner class so that we can access all these private fields
     * defined above to keep track of the parsing process
     */
    private class BugzillaReader extends DefaultHandler {

        // PCDATA is collected in a stack as well...
        private Stack pcdataStack = new Stack();

        private BugzillaReader() {
            super();
        }

        public void startDocument() {
            Logger.DEBUG("Start reading Bugzilla XML.", log);
            bugData = new Hashtable();
            bugData.put("people", new SWAMPHashSet());
            bugData.put("description", "");
            errormsg = null;
        }

        public void endDocument() {
            Logger.DEBUG("Finished reading Bugzilla XML.", log);
        }

        public void startElement(String uri, String name, String qName, Attributes atts) {
            pcdataStack.push(new String());
            Logger.DEBUG("Start of Element " + qName, log);
            if (qName.equals("bug")) {
                for (int i = 0; i < atts.getLength(); i++) {
                    if (atts.getQName(i).equals("error")) {
                        Logger.ERROR("Bugzilla Error: " + atts.getValue(i), log);
                        errormsg = "Bugzilla Error: " + atts.getValue(i).toString();
                    }
                }
            }
        }

        public void endElement(String uri, String name, String qName) {
            String pcdata = "";
            if (!pcdataStack.empty()) {
                pcdata = ((String) pcdataStack.pop());
            }
            // adding the values to the hash
            Logger.DEBUG("End of Element " + qName + " with value " + pcdata.trim(), log);
            bugData.put(qName, pcdata);

            if (qName.equals("who") || qName.equals("cc") || qName.equals("reporter")
                    || qName.equals("assigned_to")) {
                SWAMPHashSet people = (SWAMPHashSet) bugData.get("people");
                people.add(pcdata);
            } else if (qName.equals("delta_ts")) {
                DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                try {
                    bugData.put("delta", df1.parse(pcdata));
                } catch (ParseException e) {
                    Logger.ERROR("Cannot parse delta time: " + pcdata, log);
                }
            } else if (qName.equals("thetext")) {
                if (bugData.get("description").equals("")) {
                    bugData.put("description", pcdata);
                }
            }
        }

        public void characters(char ch[], int start, int length) {
            String oldpcdata = "";
            String pcdata = new String(ch, start, length);
            Logger.DEBUG("Reading characters:" + pcdata.trim(), log);

            if (!pcdataStack.empty()) {
                oldpcdata = (String) pcdataStack.pop();
            }
            pcdata = oldpcdata + pcdata;
            /* Put new value for pcdata on stack */
            pcdataStack.push(pcdata);
        }
    }
}