001: /*
002: * Copyright (c) 2006, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: /*
018: * $Id: IMAppender.java,v 1.2 2003/07/02 22:00:08 luque Exp $
019: *
020: * Copyright (c) 2003. Orange Software S.L. All Rights Reserved.
021: * Authored by Rafael Luque & Ruth Zamorano
022: *
023: * You may study, use, modify, and distribute this software for any
024: * purpose provided that this copyright notice appears in all copies.
025: *
026: * This software is provided WITHOUT WARRANTY either expressed or
027: * implied.
028: *
029: */
030:
031: package org.wso2.esb.logging;
032:
033: import org.apache.log4j.AppenderSkeleton;
034: import org.apache.log4j.Layout;
035: import org.apache.log4j.helpers.CyclicBuffer;
036: import org.apache.log4j.helpers.LogLog;
037: import org.apache.log4j.helpers.OptionConverter;
038: import org.apache.log4j.spi.ErrorCode;
039: import org.apache.log4j.spi.LoggingEvent;
040: import org.apache.log4j.spi.TriggeringEventEvaluator;
041: import org.jivesoftware.smack.Chat;
042: import org.jivesoftware.smack.GroupChat;
043: import org.jivesoftware.smack.SSLXMPPConnection;
044: import org.jivesoftware.smack.XMPPConnection;
045:
046: /**
047: * IMAppender appends tracing requests through instant
048: * messaging network.
049: *
050: * @author Rafael Luque & Ruth Zamorano
051: * @version $Revision: 1.2 $
052: */
053:
054: public class IMAppender extends AppenderSkeleton {
055:
056: // ----------------------------------------------- Variables
057:
058: private String host;
059: private int port = 5222;
060: private String username;
061: private String password;
062: private String recipient;
063: private boolean chatroom = false;
064: private String nickname;
065: private boolean SSL = false;
066: private int bufferSize = 16;
067:
068: protected TriggeringEventEvaluator evaluator;
069: protected CyclicBuffer cb;
070: protected XMPPConnection con;
071: protected Chat chat;
072: protected GroupChat groupchat;
073:
074: // -------------------------------------------- Constructors
075:
076: /**
077: * The default constructor will instantiate the appender with a
078: * default TriggeringEventEvaluator that will trigger on events
079: * with level ERROR or higher.
080: */
081: public IMAppender() {
082: this (new DefaultEvaluator());
083: }
084:
085: public IMAppender(TriggeringEventEvaluator evaluator) {
086: this .evaluator = evaluator;
087: }
088:
089: // ------------------------------- Setter and getter methods
090:
091: public String getHost() {
092: return this .host;
093: }
094:
095: public void setHost(String host) {
096: this .host = host;
097: }
098:
099: public int getPort() {
100: return this .port;
101: }
102:
103: public void setPort(int port) {
104: this .port = port;
105: }
106:
107: public String getUsername() {
108: return this .username;
109: }
110:
111: public void setUsername(String username) {
112: this .username = username;
113: }
114:
115: public String getPassword() {
116: return this .password;
117: }
118:
119: public void setPassword(String password) {
120: this .password = password;
121: }
122:
123: public String getRecipient() {
124: return this .recipient;
125: }
126:
127: public void setRecipient(String recipient) {
128: this .recipient = recipient;
129: }
130:
131: public boolean isChatroom() {
132: return this .chatroom;
133: }
134:
135: public void setChatroom(boolean chatroom) {
136: this .chatroom = chatroom;
137: }
138:
139: public String getNickname() {
140: return this .nickname;
141: }
142:
143: public void setNickname(String nickname) {
144: this .nickname = nickname;
145: }
146:
147: public boolean isSSL() {
148: return this .SSL;
149: }
150:
151: public void setSSL(boolean SSL) {
152: this .SSL = SSL;
153: }
154:
155: public int getBufferSize() {
156: return this .bufferSize;
157: }
158:
159: public void setBufferSize(int bufferSize) {
160: this .bufferSize = bufferSize;
161: }
162:
163: /**
164: * The <b>EvaluatorClass</b> option takes a string value
165: * representing the name of the class implementing the {@link
166: * TriggeringEventEvaluator} interface. A corresponding object will
167: * be instantiated and assigned as the triggering event evaluator
168: * for the SMTPAppender.
169: */
170: public void setEvaluatorClass(String value) {
171: evaluator = (TriggeringEventEvaluator) OptionConverter
172: .instantiateByClassName(value,
173: TriggeringEventEvaluator.class, evaluator);
174: }
175:
176: public String getEvaluatorClass() {
177: return evaluator == null ? null : evaluator.getClass()
178: .getName();
179: }
180:
181: // ---------------------------------- Log4j callback methods
182:
183: /**
184: * Options are activated and become effective only after calling
185: * this method.
186: */
187: public void activateOptions() {
188: try {
189: cb = new CyclicBuffer(bufferSize);
190:
191: // Create a connection to the XMPP server
192: LogLog.debug("Stablishing connection with XMPP server");
193: if (SSL) {
194: con = new SSLXMPPConnection(host, port);
195: } else {
196: con = new XMPPConnection(host, port);
197: }
198:
199: // Most servers require you to login before performing other tasks
200: LogLog.debug("About to login as [" + username + "/"
201: + password + "]");
202: con.login(username, password);
203:
204: // Start a conversation with IMAddress
205: if (chatroom) {
206: LogLog.debug("About to create ChatGroup");
207: groupchat = con.createGroupChat(recipient);
208: LogLog.debug("About to join room");
209: groupchat.join(nickname != null ? nickname : username);
210: } else {
211: chat = con.createChat(recipient);
212: }
213:
214: } catch (Exception e) {
215: errorHandler.error(
216: "Error while activating options for appender named ["
217: + name + "]", e, ErrorCode.GENERIC_FAILURE);
218: }
219: }
220:
221: /**
222: * Close this IMAppender. Closing all resources used by the
223: * appender. A closed appender cannot be re-opened.
224: */
225: public synchronized void close() {
226: if (this .closed)
227: return;
228:
229: LogLog.debug("Closing appender [" + name + "]");
230: this .closed = true;
231:
232: // Closes the connection by setting presence to unavailable
233: // then closing the stream to the XMPP server.
234: if (con != null)
235: con.close();
236:
237: // Help GC
238: con = null;
239: chat = null;
240: groupchat = null;
241: }
242:
243: /**
244: * This method called by {@link AppenderSkeleton#doAppend} method
245: * does most of the real appending work. Adds the event to a buffer
246: * and checks if the event triggers a message to be sent.
247: */
248: public void append(LoggingEvent event) {
249:
250: // check pre-conditions
251: if (!checkEntryConditions()) {
252: return;
253: }
254:
255: cb.add(event);
256: if (evaluator.isTriggeringEvent(event)) {
257: sendBuffer();
258: }
259: }
260:
261: /**
262: * Send the contents of the cyclic buffer as an IM message.
263: */
264: protected void sendBuffer() {
265: try {
266: StringBuffer buf = new StringBuffer();
267:
268: int len = cb.length();
269: for (int i = 0; i < len; i++) {
270: LoggingEvent event = cb.get();
271: buf.append(layout.format(event));
272: // if layout doesn't handle exception, the appender has to do it
273: if (layout.ignoresThrowable()) {
274: String[] s = event.getThrowableStrRep();
275: if (s != null) {
276: for (int j = 0; j < s.length; j++) {
277: buf.append(Layout.LINE_SEP);
278: buf.append(s[j]);
279: }
280: }
281: }
282: }
283:
284: if (chatroom) {
285: groupchat.sendMessage(buf.toString());
286: } else {
287: chat.sendMessage(buf.toString());
288: }
289:
290: } catch (Exception e) {
291: errorHandler.error("Could not send message in IMAppender ["
292: + name + "]", e, ErrorCode.GENERIC_FAILURE);
293: }
294: }
295:
296: /**
297: * This method determines if there is a sense in attempting to append.
298: * <p/>
299: * <p>It checks whether there is an output chat available and also if
300: * there is a set layout. If these checks fail, then the boolean
301: * value <code>false</code> is returned.
302: */
303: protected boolean checkEntryConditions() {
304: if ((this .chat == null) && (this .groupchat == null)) {
305: errorHandler.error("Chat object not configured");
306: return false;
307: }
308:
309: if (this .layout == null) {
310: errorHandler.error("No layout set for appender named ["
311: + name + "]");
312: return false;
313: }
314: return true;
315: }
316:
317: /**
318: * The IMAppender requires a layout. Hence, this method returns
319: * <code>true</code>.
320: */
321: public boolean requiresLayout() {
322: return true;
323: }
324: }
|