001: /********************************************************************************
002: * CruiseControl, a Continuous Integration Toolkit
003: * Copyright (c) 2001-2003, ThoughtWorks, Inc.
004: * 200 E. Randolph, 25th Floor
005: * Chicago, IL 60601 USA
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * + Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * + Redistributions in binary form must reproduce the above
016: * copyright notice, this list of conditions and the following
017: * disclaimer in the documentation and/or other materials provided
018: * with the distribution.
019: *
020: * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
021: * names of its contributors may be used to endorse or promote
022: * products derived from this software without specific prior
023: * written permission.
024: *
025: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
026: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
027: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
028: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
029: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
030: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
031: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
032: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
033: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
034: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
035: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
036: ********************************************************************************/package net.sourceforge.cruisecontrol.publishers;
037:
038: import net.sourceforge.cruisecontrol.CruiseControlException;
039: import net.sourceforge.cruisecontrol.Publisher;
040: import net.sourceforge.cruisecontrol.util.ValidationHelper;
041: import net.sourceforge.cruisecontrol.util.XMLLogHelper;
042: import org.apache.log4j.Logger;
043: import org.jdom.Element;
044: import org.jivesoftware.smack.Chat;
045: import org.jivesoftware.smack.GroupChat;
046: import org.jivesoftware.smack.SSLXMPPConnection;
047: import org.jivesoftware.smack.XMPPConnection;
048: import org.jivesoftware.smack.XMPPException;
049:
050: /**
051: * Abstract publisher which establishes this transport to publish
052: * build results via Jabber Instant Messaging framework.
053: *
054: * @author <a href="mailto:jonas_edgeworth@cal.berkeley.edu">Jonas Edgeworth</a>
055: * @version 1.0
056: * @see LinkJabberPublisher
057: */
058:
059: public abstract class JabberPublisher implements Publisher {
060:
061: private static final Logger LOG = Logger
062: .getLogger(JabberPublisher.class);
063:
064: private String host;
065: private int port = 5222;
066: private String username;
067: private String password;
068: private String recipient;
069: private String service;
070:
071: private boolean chatroom = false;
072: private boolean ssl = false;
073:
074: // one connection for the CC session
075: private static XMPPConnection connection;
076: private Chat chat;
077: private GroupChat groupchat;
078:
079: public void setHost(String host) {
080: this .host = host;
081: }
082:
083: public void setPort(int port) {
084: this .port = port;
085: }
086:
087: public void setUsername(String username) {
088: this .username = username;
089: }
090:
091: public void setPassword(String password) {
092: this .password = password;
093: }
094:
095: public void setRecipient(String recipient) {
096: this .recipient = recipient;
097: }
098:
099: public void setService(String service) {
100: this .service = service;
101: }
102:
103: public void setChatroom(boolean chatroom) {
104: this .chatroom = chatroom;
105: }
106:
107: public void setSsl(boolean ssl) {
108: this .ssl = ssl;
109: }
110:
111: /**
112: * Initialize the XMPPConnection to the Jabber server and
113: * create the necessary chat session to send a message.
114: */
115: protected void init() {
116: // Uncommenting will execute Smack XML-RPC trace GUI
117: //XMPPConnection.DEBUG_ENABLED = true;
118: if (null == connection || requiresReconnect()) {
119: try {
120: if (ssl) {
121: if (service != null) {
122: connection = new SSLXMPPConnection(host, port,
123: service);
124: } else {
125: connection = new SSLXMPPConnection(host, port);
126: }
127: } else {
128: if (service != null) {
129: connection = new XMPPConnection(host, port,
130: service);
131: } else {
132: connection = new XMPPConnection(host, port);
133: }
134: }
135: } catch (XMPPException e) {
136: LOG.error("Error initializing jabber connection", e);
137: }
138: try {
139: connection.login(username, password);
140: } catch (XMPPException e) {
141: LOG.error("Authentication error on login", e);
142: }
143: }
144:
145: try {
146: if (chatroom) {
147: groupchat = connection.createGroupChat(recipient);
148: groupchat.join(username);
149: } else {
150: chat = connection.createChat(recipient);
151: }
152: } catch (XMPPException e) {
153: LOG.error(
154: "Could not send message to recipient or chat room",
155: e);
156: }
157: }
158:
159: /**
160: * Checks for changes to params or connection failure
161: *
162: * @return true if a reconnect is required
163: */
164: private boolean requiresReconnect() {
165: return (!connection.isConnected() && !connection
166: .isSecureConnection())
167: || !connection.isAuthenticated();
168: }
169:
170: /**
171: * Validate that all the mandatory parameters were specified in order
172: * to properly initial the Jabber client service. Note that this is called
173: * after the configuration file is read.
174: *
175: * @throws CruiseControlException if there was a configuration error.
176: */
177: public void validate() throws CruiseControlException {
178:
179: ValidationHelper.assertIsSet(host, "host", this .getClass());
180: ValidationHelper.assertIsSet(username, "username", this
181: .getClass());
182: ValidationHelper
183: .assertFalse(
184: isEmail(username),
185: "'username' is not in correct format. "
186: + "'username' should not be of the form user@domain.com");
187:
188: ValidationHelper.assertIsSet(password, "password", this
189: .getClass());
190: ValidationHelper.assertIsSet(recipient, "recipient", this
191: .getClass());
192: ValidationHelper
193: .assertTrue(
194: isEmail(recipient),
195: "'recipient' is not in correct format. "
196: + "'recipient' should be of the form user@domain.com");
197: }
198:
199: private boolean isEmail(final String username) {
200: return username.indexOf("@") != -1;
201: }
202:
203: /**
204: * Publish the results to the Jabber transport via an instant message.
205: *
206: * @param cruisecontrolLog
207: * @throws CruiseControlException
208: */
209: public void publish(Element cruisecontrolLog)
210: throws CruiseControlException {
211:
212: // Initialize the XMPP connection
213: init();
214:
215: // Generate the message to be sent to the recipient
216: XMLLogHelper helper = new XMLLogHelper(cruisecontrolLog);
217: String message = createMessage(helper);
218:
219: // Send the message to the recipient
220: try {
221: if (chatroom) {
222: groupchat.sendMessage(message);
223: } else {
224: chat.sendMessage(message);
225: }
226: } catch (XMPPException e) {
227: LOG.error("Unable to send message via Jabber", e);
228: }
229: }
230:
231: /**
232: * Creates the IM message body to be sent to the recipient.
233: *
234: * @return <code>String</code> that makes up the body of the IM message
235: * @throws CruiseControlException
236: */
237: protected abstract String createMessage(XMLLogHelper logHelper)
238: throws CruiseControlException;
239:
240: }
|