/**
* Created on Dec 6, 2006 9:25:19 AM
*/
package hudson.plugins.ircbot;
import hudson.Extension;
import hudson.Util;
import hudson.model.AbstractProject;
import hudson.model.User;
import hudson.plugins.im.GroupChatIMMessageTarget;
import hudson.plugins.im.IMConnection;
import hudson.plugins.im.IMException;
import hudson.plugins.im.IMMessageTarget;
import hudson.plugins.im.IMMessageTargetConverter;
import hudson.plugins.im.IMPublisher;
import hudson.plugins.im.IMPublisherDescriptor;
import hudson.plugins.im.NotificationStrategy;
import hudson.plugins.im.tools.ExceptionHelper;
import hudson.plugins.ircbot.v2.IRCConnectionProvider;
import hudson.plugins.ircbot.v2.IRCMessageTargetConverter;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Publisher;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.StaplerRequest;
/**
* Publishes build results to IRC channels.
*
* @author bruyeron
* @author $Author$ (last change)
* @version $Id$
*/
public class IrcPublisher extends IMPublisher {
private static final Logger LOGGER = Logger.getLogger(IrcPublisher.class.getName());
/**
* Descriptor should be singleton.
*/
@Extension
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
private static final IMMessageTargetConverter CONVERTER = new IRCMessageTargetConverter();
/**
* channels to notify with build status If not empty, this replaces the main
* channels defined at the descriptor level.
* @deprecated only used to deserialize old instances. please use {@link #getNotificationTargets()}
*/
@Deprecated
public List<String> channels = new ArrayList<String>();
public IrcPublisher(List<IMMessageTarget> defaultTargets, String notificationStrategy,
boolean notifyGroupChatsOnBuildStart,
boolean notifySuspects,
boolean notifyCulprits,
boolean notifyFixers,
boolean notifyUpstreamCommitters)
{
super(defaultTargets, notificationStrategy, notifyGroupChatsOnBuildStart,
notifySuspects, notifyCulprits, notifyFixers, notifyUpstreamCommitters);
}
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.BUILD;
}
/**
* @see hudson.model.Describable#getDescriptor()
*/
@Override
public BuildStepDescriptor<Publisher> getDescriptor() {
return DESCRIPTOR;
}
// from IMPublisher:
@Override
protected String getConfiguredIMId(User user) {
IrcUserProperty ircUserProperty = (IrcUserProperty) user.getProperties().get(IrcUserProperty.DESCRIPTOR);
if (ircUserProperty != null) {
return ircUserProperty.getNick();
}
return null;
}
@Override
protected IMConnection getIMConnection() throws IMException {
return IRCConnectionProvider.getInstance().currentConnection();
}
@Override
protected String getPluginName() {
return "IRC notifier plugin";
}
// deserialize/migrate old instances
@SuppressWarnings("deprecation")
private Object readResolve() {
if (this.getNotificationTargets() == null) {
if (this.channels != null) {
List<IMMessageTarget> targets = new ArrayList<IMMessageTarget>(this.channels.size());
for (String channel : channels) {
targets.add(new GroupChatIMMessageTarget(channel));
}
setNotificationTargets(targets);
} else {
setNotificationTargets(Collections.<IMMessageTarget>emptyList());
}
}
this.channels = null;
if (getNotificationStrategy() == null) {
// set to the fixed strategy in ircbot <= 1.7
setNotificationStrategy(NotificationStrategy.STATECHANGE_ONLY);
}
return this;
}
/**
* Descriptor for {@link IrcPublisher}
*/
public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> implements IMPublisherDescriptor {
private static final String PREFIX = "irc_publisher.";
public static final String PARAMETERNAME_STRATEGY = PREFIX + "strategy";
public static final String PARAMETERNAME_NOTIFY_START = PREFIX + "notifyStart";
public static final String PARAMETERNAME_NOTIFY_SUSPECTS = PREFIX + "notifySuspects";
public static final String PARAMETERNAME_NOTIFY_CULPRITS = PREFIX + "notifyCulprits";
public static final String PARAMETERNAME_NOTIFY_FIXERS = PREFIX + "notifyFixers";
public static final String PARAMETERNAME_NOTIFY_UPSTREAM_COMMITTERS = PREFIX + "notifyUpstreamCommitters";
public static final String PARAMETERVALUE_STRATEGY_DEFAULT = NotificationStrategy.STATECHANGE_ONLY.getDisplayName();;
public static final String[] PARAMETERVALUE_STRATEGY_VALUES = NotificationStrategy.getDisplayNames();
public static final String PARAMETERNAME_HUDSON_LOGIN = PREFIX + "hudsonLogin";
public static final String PARAMETERNAME_HUDSON_PASSWORD = PREFIX + "hudsonPassword";
public static final String PARAMETERNAME_USE_NOTICE = PREFIX + "useNotice";
public static final String PARAMETERNAME_NICKSERV_PASSWORD = PREFIX + "nickServPassword";
boolean enabled = false;
String hostname = null;
Integer port = 194;
String password = null;
String nick = null;
String nickServPassword = null;
/**
* channels to join
*
* @deprecated Only to deserialize old descriptors
*/
@Deprecated
List<String> channels;
private List<IMMessageTarget> defaultTargets;
String commandPrefix = null;
private String hudsonLogin;
private String hudsonPassword;
private boolean useNotice;
DescriptorImpl() {
super(IrcPublisher.class);
load();
if (isEnabled()) {
try {
IRCConnectionProvider.setDesc(this);
} catch (final Exception e) {
// Server temporarily unavailable or misconfigured?
LOGGER.warning(ExceptionHelper.dump(e));
}
} else {
try {
IRCConnectionProvider.setDesc(null);
} catch (IMException e) {
// ignore
}
}
}
/**
* @see hudson.model.Descriptor#configure(org.kohsuke.stapler.StaplerRequest)
*/
@Override
public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
this.enabled = "on".equals(req.getParameter("irc_publisher.enabled"))
|| "true".equals(req.getParameter("irc_publisher.enabled"));
if (this.enabled) {
this.hostname = req.getParameter("irc_publisher.hostname");
this.password = req.getParameter("irc_publisher.password");
this.nick = req.getParameter("irc_publisher.nick");
this.nickServPassword = req.getParameter(PARAMETERNAME_NICKSERV_PASSWORD);
try {
this.port = Integer.valueOf(req.getParameter("irc_publisher.port"));
} catch (NumberFormatException e) {
throw new FormException("port field must be an Integer",
"irc_publisher.port");
}
this.commandPrefix = req.getParameter("irc_publisher.commandPrefix");
this.commandPrefix = Util.fixEmptyAndTrim(commandPrefix);
String[] channelsNames = req.getParameterValues("irc_publisher.channel.name");
String[] channelsPasswords = req.getParameterValues("irc_publisher.channel.password");
List<IMMessageTarget> targets = Collections.emptyList();
if (channelsNames != null) {
targets = new ArrayList<IMMessageTarget>(channelsNames.length);
for (int i=0; i < channelsNames.length; i++) {
if (Util.fixEmptyAndTrim(channelsNames[i]) == null) {
throw new FormException("Channel name must not be empty", "channel.name");
}
if (Util.fixEmpty(channelsNames[i]) != null) {
targets.add(new GroupChatIMMessageTarget(channelsNames[i], channelsPasswords[i]));
} else {
targets.add(new GroupChatIMMessageTarget(channelsNames[i]));
}
}
}
this.defaultTargets = targets;
this.hudsonLogin = req.getParameter(PARAMETERNAME_HUDSON_LOGIN);
this.hudsonPassword = req.getParameter(PARAMETERNAME_HUDSON_PASSWORD);
this.useNotice = "on".equals(req.getParameter(PARAMETERNAME_USE_NOTICE));
// try to establish the connection
try {
IRCConnectionProvider.setDesc(this);
IRCConnectionProvider.getInstance().currentConnection();
} catch (final Exception e) {
LOGGER.warning(ExceptionHelper.dump(e));
}
} else {
IRCConnectionProvider.getInstance().releaseConnection();
try {
IRCConnectionProvider.setDesc(null);
} catch (IMException e) {
// ignore
}
}
save();
return super.configure(req, formData);
}
/**
* @see hudson.model.Descriptor#getDisplayName()
*/
@Override
public String getDisplayName() {
return "IRC Notification";
}
/**
* @see hudson.model.Descriptor#getHelpFile()
*/
@Override
public String getHelpFile() {
return "/plugin/ircbot/help.html";
}
/**
* @see hudson.model.Descriptor#newInstance(org.kohsuke.stapler.StaplerRequest)
*/
@Override
public Publisher newInstance(StaplerRequest req, JSONObject formData) throws FormException {
String[] channelsNames = req.getParameterValues("irc_publisher.channel.name");
String[] channelsPasswords = req.getParameterValues("irc_publisher.channel.password");
List<IMMessageTarget> targets = Collections.emptyList();
if (channelsNames != null) {
targets = new ArrayList<IMMessageTarget>(channelsNames.length);
for (int i=0; i < channelsNames.length; i++) {
if (Util.fixEmptyAndTrim(channelsNames[i]) == null) {
throw new FormException("Channel name must not be empty", "channel.name");
}
if (Util.fixEmpty(channelsNames[i]) != null) {
targets.add(new GroupChatIMMessageTarget(channelsNames[i], channelsPasswords[i]));
} else {
targets.add(new GroupChatIMMessageTarget(channelsNames[i]));
}
}
}
String n = req.getParameter(PARAMETERNAME_STRATEGY);
if (n == null) {
n = PARAMETERVALUE_STRATEGY_DEFAULT;
} else {
boolean foundStrategyValueMatch = false;
for (final String strategyValue : PARAMETERVALUE_STRATEGY_VALUES) {
if (strategyValue.equals(n)) {
foundStrategyValueMatch = true;
break;
}
}
if (! foundStrategyValueMatch) {
n = PARAMETERVALUE_STRATEGY_DEFAULT;
}
}
boolean notifyStart = "on".equals(req.getParameter(PARAMETERNAME_NOTIFY_START));
boolean notifySuspects = "on".equals(req.getParameter(PARAMETERNAME_NOTIFY_SUSPECTS));
boolean notifyCulprits = "on".equals(req.getParameter(PARAMETERNAME_NOTIFY_CULPRITS));
boolean notifyFixers = "on".equals(req.getParameter(PARAMETERNAME_NOTIFY_FIXERS));
boolean notifyUpstream = "on".equals(req.getParameter(PARAMETERNAME_NOTIFY_UPSTREAM_COMMITTERS));
return new IrcPublisher(targets, n, notifyStart, notifySuspects, notifyCulprits,
notifyFixers, notifyUpstream);
}
@Override
@SuppressWarnings("unchecked")
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return true;
}
/**
* @return the commandPrefix
*/
@Override
public String getCommandPrefix() {
return commandPrefix;
}
/**
* @return the hostname
*/
@Override
public String getHostname() {
return hostname;
}
/**
* Returns the nickname that should be used to identify against the IRC server.
*
* @return the nick
*/
public String getNick() {
return nick;
}
/**
* Returns the password that should be used to try and identify
* with NickServ.
*/
public String getNickServPassword() {
return nickServPassword;
}
@Override
public String getPassword() {
return password;
}
@Override
public int getPort() {
return port;
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public String getDefaultIdSuffix() {
// not implemented for IRC, yet
return null;
}
@Override
public String getHost() {
return this.hostname;
}
@Override
public String getHudsonUserName() {
return this.hudsonLogin;
}
@Override
public String getHudsonPassword() {
return this.hudsonPassword;
}
@Override
public String getPluginDescription() {
return "IRC notifier plugin";
}
@Override
public String getUserName() {
return this.nick;
}
@Override
public boolean isExposePresence() {
return true;
}
@Override
public List<IMMessageTarget> getDefaultTargets() {
if (this.defaultTargets == null) {
return Collections.emptyList();
}
return this.defaultTargets;
}
@Override
public IMMessageTargetConverter getIMMessageTargetConverter() {
return CONVERTER;
}
/**
* Specifies if the bot should use the /notice command
* instead of the /msg command to notify.
*/
public boolean isUseNotice() {
return this.useNotice;
}
/**
* Deserialize old descriptors.
*/
private Object readResolve() {
if (this.defaultTargets == null) {
if (this.channels != null) {
this.defaultTargets = new ArrayList<IMMessageTarget>(this.channels.size());
for (String channel : this.channels) {
this.defaultTargets.add(new GroupChatIMMessageTarget(channel));
}
this.channels = null;
save();
}
}
return this;
}
}
}