/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2007-2011 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) 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 OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.netmgt.ticketer.jira; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.rmi.RemoteException; import java.util.Calendar; import java.util.Properties; import org.apache.commons.io.IOUtils; import org.opennms.api.integration.ticketing.Plugin; import org.opennms.api.integration.ticketing.Ticket; import org.opennms.core.utils.ThreadCategory; import com.atlassian.jira.rpc.soap.client.JiraSoapService; import com.atlassian.jira.rpc.soap.client.JiraSoapServiceService; import com.atlassian.jira.rpc.soap.client.JiraSoapServiceServiceLocator; import com.atlassian.jira.rpc.soap.client.RemoteComment; import com.atlassian.jira.rpc.soap.client.RemoteFieldValue; import com.atlassian.jira.rpc.soap.client.RemoteIssue; /** * OpenNMS Trouble Ticket Plugin API implementation for Jira * * @author <a href="mailto:joed@opennms.org">Johan Edstrom</a> */ /* * This class uses the Codehaus Swizzle-Jira library * to manipulate issues via the RPC gateway. * @author joed@opennms.org * */ public class JiraTicketerPlugin implements Plugin { /* * @returns JiraConnection */ private class JiraConnection { public JiraSoapService jira = null; public String token = null; public JiraSoapService getJira() { return jira; } public void setJira(JiraSoapService jira) { this.jira = jira; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } } JiraConnection getConnection() { JiraConnection jira = new JiraConnection(); JiraSoapServiceService jiraSoapServiceGetter = new JiraSoapServiceServiceLocator(); URL jiraUrl = null; try { jiraUrl = new URL(getProperties().getProperty("jira.host")); } catch (MalformedURLException e) { log().error("Failed to parse url " + jiraUrl); } try { jira.setJira(jiraSoapServiceGetter.getJirasoapserviceV2(jiraUrl)); } catch (Throwable e) { log().error("Failed initialzing JiraConnection" + e); } log().debug("Jira factory: " + jiraSoapServiceGetter.getJirasoapserviceV2Address()); try { jira.setToken(jira.getJira().login(getProperties().getProperty("jira.username"), getProperties().getProperty("jira.password"))); } catch (Throwable e) { log().error("Login failure: " + e); } return jira; } /** * Implementation of TicketerPlugin API call to retrieve a Jira trouble ticket. * * @return an OpenNMS */ public Ticket get(String ticketId) { JiraConnection jira = getConnection(); RemoteIssue issue = new RemoteIssue(); // w00t try { issue = jira.getJira().getIssue(jira.getToken(), ticketId); } catch (RemoteException e) { log().error("Error fetching issue: " + ticketId + " " + e); } Ticket ticket = new Ticket(); if (issue != null) { ticket.setId(issue.getKey()); ticket.setModificationTimestamp(String.valueOf(issue.getUpdated().getTime())); ticket.setSummary(issue.getSummary()); RemoteComment[] comments = null; try { comments = jira.getJira().getComments(jira.getToken(), ticketId); } catch (RemoteException e) { log().error("Error retreiving remote comments " + e); } String allComments = ""; if (comments != null) { for (RemoteComment comment : comments) { allComments = allComments + "\n" + comment.getAuthor() + "\n" + comment.getAuthor(); } } ticket.setDetails(allComments); ticket.setState(getStateFromId(issue.getStatus().toUpperCase())); } return ticket; } private int openNMSToJira(Ticket.State state) { switch (state) { case OPEN: return 1; case CANCELLED: return 10033; case CLOSED: //Resolved return 5; default: return 1; } } /** * Convenience method for converting a string representation of * the OpenNMS enumerated ticket states. * * @param stateIdString * @return the converted <code>org.opennms.api.integration.ticketing.Ticket.State</code> */ private Ticket.State getStateFromId(String stateIdString) { if (stateIdString == null) { return Ticket.State.OPEN; } int stateId = Integer.parseInt(stateIdString); switch (stateId) { case 1: return Ticket.State.OPEN; case 2: return Ticket.State.OPEN; case 3: return Ticket.State.OPEN; case 4: return Ticket.State.OPEN; case 5: return Ticket.State.CLOSED; case 6: return Ticket.State.CANCELLED; case 7: return Ticket.State.CANCELLED; default: return Ticket.State.OPEN; } } /** * Retrieves the properties defined in the jira.properties file. * * @return a <code>java.util.Properties object containing jira plugin defined properties */ private Properties getProperties() { File home = new File(System.getProperty("opennms.home")); File etc = new File(home, "etc"); File config = new File(etc, "jira.properties"); Properties props = new Properties(); InputStream in = null; try { in = new FileInputStream(config); props.load(in); } catch (IOException e) { log().error("Unable to load " + config + " ignoring.", e); } finally { IOUtils.closeQuietly(in); } log().debug("Loaded user: " + props.getProperty("jira.username")); log().debug("Loaded type: " + props.getProperty("jira.type")); return props; } /* * (non-Javadoc) * @see org.opennms.api.integration.ticketing.Plugin#saveOrUpdate(org.opennms.api.integration.ticketing.Ticket) */ public void saveOrUpdate(Ticket ticket) { JiraConnection jira = getConnection(); RemoteIssue issue = new RemoteIssue(); issue.setProject(getProperties().getProperty("jira.project")); issue.setReporter(getProperties().getProperty("jira.username")); issue.setType(getProperties().getProperty("jira.type").trim()); issue.setSummary(ticket.getSummary()); issue.setDescription(ticket.getSummary()); issue.setDuedate(Calendar.getInstance()); if (ticket.getId() == null || ticket.getId().equals("")) { try { RemoteIssue addedIssue = jira.getJira().createIssue(jira.getToken(), issue); ticket.setId(addedIssue.getKey()); RemoteComment comment = new RemoteComment(); comment.setBody(ticket.getDetails()); comment.setAuthor(getProperties().getProperty("jira.username")); jira.getJira().addComment(jira.getToken(), ticket.getId(), comment); log().error("Ticket ID: " + addedIssue.getKey()); } catch (Throwable e) { log().error("Error: Could not create a Jira issue id " + e); } } else { log().info("Received ticket: " + ticket.getId()); try { issue = jira.getJira().getIssue(jira.getToken(), ticket.getId()); } catch (RemoteException e) { log().error("Error: could not retrive remote issue"); } if ("closed".equals(ticket.getState().toString().toLowerCase())) { log().info("Closing ticket " + ticket.getId()); RemoteComment comment = new RemoteComment(); comment.setBody("Issue resolved by OpenNMS"); try { jira.getJira().addComment(jira.getToken(), issue.getKey(), comment); } catch (RemoteException e) { log().error("Could not append comments " + e); } RemoteFieldValue[] resolution = new RemoteFieldValue[0]; try { jira.getJira().progressWorkflowAction(jira.getToken(), ticket.getId(), String.valueOf(openNMSToJira(ticket.getState())), resolution); ticket.setState(Ticket.State.CLOSED); } catch (RemoteException e) { log().error("Error: Could not resolve ticket"); } } // This case is most likely never used. if ("open".equals(ticket.getState().toString().toLowerCase())) { log().info("Re-Opening ticket " + ticket.getId()); RemoteFieldValue[] resolution = new RemoteFieldValue[0]; try { jira.getJira().progressWorkflowAction(jira.getToken(), ticket.getId(), String.valueOf(openNMSToJira(ticket.getState())), resolution); ticket.setState(Ticket.State.OPEN); } catch (RemoteException e) { log().error("Error: Could not re-open ticket"); } } } } /** * Convenience logging. * * @return a log4j Category for this class */ private ThreadCategory log() { return ThreadCategory.getInstance(getClass()); } }