/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2008-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.rt;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.opennms.api.integration.ticketing.Plugin;
import org.opennms.api.integration.ticketing.PluginException;
import org.opennms.api.integration.ticketing.Ticket;
import org.opennms.core.utils.LogUtils;
import org.opennms.netmgt.rt.ReadOnlyRtConfigDao;
import org.opennms.netmgt.rt.RTTicket;
import org.opennms.netmgt.rt.RequestTracker;
import org.opennms.netmgt.rt.RequestTrackerException;
/**
* OpenNMS Trouble Ticket Plugin API implementation for RT
*
* @author <a href="mailto:jonathan@opennms.org">Jonathan Sartin</a>
* @author <a href="mailto:ranger@opennms.org">Benjamin Reed</a>
*/
public class RtTicketerPlugin implements Plugin {
private static Pattern m_tagPattern = Pattern.compile("<[^>]*>");
private RequestTracker m_requestTracker;
private String m_queue;
private String m_requestor;
private String m_openStatus;
private String m_closedStatus;
private String m_cancelledStatus;
private List<Integer> m_validOpenStatus;
private List<String> m_validClosedStatus;
private List<String> m_validCancelledStatus;
/**
* <p>Constructor for RtTicketerPlugin.</p>
*/
public RtTicketerPlugin() {
ReadOnlyRtConfigDao dao = new ReadOnlyRtConfigDao();
m_openStatus = dao.getOpenStatus();
m_closedStatus = dao.getClosedStatus();
m_cancelledStatus = dao.getCancelledStatus();
m_validOpenStatus = dao.getValidOpenStatus();
m_validClosedStatus = dao.getValidClosedStatus();
m_validCancelledStatus = dao.getValidCancelledStatus();
m_queue = dao.getQueue();
m_requestor = dao.getRequestor();
m_requestTracker = new RequestTracker(dao.getBaseURL(), dao.getUsername(), dao.getPassword(), dao.getTimeout(), dao.getRetry());
}
/**
* {@inheritDoc}
*
* Gets ticket details from the RT trouble ticket system
*/
public Ticket get(final String ticketId) throws PluginException {
Ticket ticket = null;
RTTicket rtt = null;
try {
rtt = m_requestTracker.getTicket(Long.valueOf(ticketId), false);
} catch (final RequestTrackerException e) {
throw new PluginException(e);
}
if (rtt != null) {
ticket = new Ticket();
ticket.setState(rtToOpenNMSState(rtt.getStatus()));
ticket.setId(rtt.getId().toString());
ticket.setUser(StringUtils.join(rtt.getRequestors(), ", "));
ticket.setSummary(rtt.getSubject());
ticket.setDetails(rtt.getText());
} else {
throw new PluginException("could not find ticket in RT for Ticket: " + ticketId);
}
return ticket;
}
/**
* {@inheritDoc}
*
* Creates a new ticket (if none exists) or updates an existing ticket in the
* RT trouble ticket system. Ticket updates are currently limited to updating
* the ticket status only.
*/
public void saveOrUpdate(final Ticket newTicket) throws PluginException {
String newTicketID;
Ticket currentTicket = null;
try {
// If there's no external ID in the OpenNMS ticket, we need to create one
if ((newTicket.getId() == null) ) {
LogUtils.debugf(this, "TicketId is null creating a new ticket");
RTTicket ticket = rtTicketFromTicket(newTicket);
Long rtTicketNumber = null;
try {
rtTicketNumber = m_requestTracker.createTicket(ticket);
} catch (final Exception e) {
throw new PluginException(e);
}
if (rtTicketNumber == null) {
throw new PluginException("Received no ticket number from RT");
}
newTicketID = rtTicketNumber.toString();
newTicket.setId(newTicketID);
LogUtils.debugf(this, "created new ticket: %s", newTicket.getId());
} else {
currentTicket = get(newTicket.getId());
LogUtils.debugf(this, "updating existing ticket: %s", currentTicket.getId());
if (currentTicket.getState() != newTicket.getState()) {
updateRtStatus(newTicket);
} else {
// There is no else at the moment
// Tickets are _only_ updated with new state
}
}
} catch (final PluginException e) {
LogUtils.errorf(this, e, "Failed to create or update RT ticket");
throw e;
}
}
/**
* Convenience method for updating the Ticket Status in RT
*
* @param ticket the ticket details
*/
private void updateRtStatus(final Ticket ticket) throws PluginException {
try {
m_requestTracker.updateTicket(Long.valueOf(ticket.getId()), "Status: " + openNMSToRTState(ticket.getState()));
} catch (final Exception e) {
LogUtils.warnf(this, e, "Error updating ticket %s to state %s", ticket.getId(), ticket.getState().toString());
}
}
private RTTicket rtTicketFromTicket(final Ticket ticket) {
final RTTicket rtt = new RTTicket();
final String id = ticket.getId();
if (id != null && id.length() > 0) {
rtt.setId(Long.valueOf(id));
}
rtt.setQueue(m_queue);
rtt.setRequestor(m_requestor);
if (ticket.getSummary() != null) rtt.setSubject(ticket.getSummary());
// Remove any HTML tags in the ticket details.
if (ticket.getDetails() != null) rtt.setText(m_tagPattern.matcher(ticket.getDetails()).replaceAll(""));
rtt.setStatus(openNMSToRTState(ticket.getState()));
return rtt;
}
/**
* Convenience method for converting OpenNMS enumerated ticket states to
* RT status.
*
* @param state a valid <code>org.opennms.netmgt.ticketd.Ticket.State</code>.
* @return a String representing the RT Status of the ticket.
*/
private String openNMSToRTState(final Ticket.State state) {
String rtStatus;
LogUtils.debugf(this, "getting RT status from OpenNMS State %s", state.toString());
switch (state) {
case OPEN:
// ticket is new
rtStatus = m_openStatus;
LogUtils.debugf(this, "OpenNMS Status OPEN matched rt status %s", rtStatus);
break;
case CLOSED:
// closed successful
rtStatus = m_closedStatus;
LogUtils.debugf(this, "OpenNMS Status CLOSED matched rt status %s", rtStatus);
break;
case CANCELLED:
// not sure how often we see this
rtStatus = m_cancelledStatus;
LogUtils.debugf(this, "OpenNMS Status CANCELLED matched rt status %s", rtStatus);
break;
default:
LogUtils.debugf(this, "No valid OpenNMS state on ticket");
rtStatus = m_openStatus;
}
LogUtils.debugf(this, "OpenNMS state was %s, setting RT status to %s", state.toString(), rtStatus);
return rtStatus;
}
/**
* Convenience method for converting RT ticket Status to
* OpenNMS enumerated ticket states.
*
* @param rtStatus a valid RT status string
* @return the converted <code>org.opennms.netmgt.ticketd.Ticket.State</code>
*/
private Ticket.State rtToOpenNMSState(final String rtStatus) {
if (m_validOpenStatus.contains(rtStatus)) {
LogUtils.debugf(this, "RT status %s matched OpenNMS state Open", rtStatus);
return Ticket.State.OPEN;
} else if (m_validClosedStatus.contains(rtStatus)) {
LogUtils.debugf(this, "RT status %s matched OpenNMS state Closed", rtStatus);
return Ticket.State.CLOSED;
} else if (m_validCancelledStatus.contains(rtStatus)) {
LogUtils.debugf(this, "RT status %s matched OpenNMS state Cancelled", rtStatus);
return Ticket.State.CANCELLED;
}
// we don't know what it is, so default to keeping it open.
return Ticket.State.OPEN;
}
/**
* <p>setUser</p>
*
* @param user a {@link java.lang.String} object.
*/
public void setUser(final String user) {
m_requestTracker.setUser(user);
}
/**
* <p>setPassword</p>
*
* @param password a {@link java.lang.String} object.
*/
public void setPassword(final String password) {
m_requestTracker.setPassword(password);
}
}