1/*
2 * Conditions Of Use
3 *
4 * This software was developed by employees of the National Institute of
5 * Standards and Technology (NIST), an agency of the Federal Government.
6 * Pursuant to title 15 Untied States Code Section 105, works of NIST
7 * employees are not subject to copyright protection in the United States
8 * and are considered to be in the public domain.  As a result, a formal
9 * license is not needed to use the software.
10 *
11 * This software is provided by NIST as a service and is expressly
12 * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13 * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15 * AND DATA ACCURACY.  NIST does not warrant or make any representations
16 * regarding the use of the software or the results thereof, including but
17 * not limited to the correctness, accuracy, reliability or usefulness of
18 * the software.
19 *
20 * Permission to use this software is contingent upon your acceptance
21 * of the terms of this agreement
22 *
23 * .
24 *
25 */
26/*******************************************************************************
27 * Product of NIST/ITL Advanced Networking Technologies Division (ANTD).       *
28 ******************************************************************************/
29
30package gov.nist.javax.sip.stack;
31
32import gov.nist.core.ServerLogger;
33import gov.nist.core.StackLogger;
34import gov.nist.javax.sip.LogRecord;
35import gov.nist.javax.sip.header.CallID;
36import gov.nist.javax.sip.message.SIPMessage;
37
38import java.io.File;
39import java.io.FileWriter;
40import java.io.IOException;
41import java.io.PrintWriter;
42import java.util.Properties;
43
44import javax.sip.SipStack;
45import javax.sip.header.TimeStampHeader;
46
47// BEGIN android-deleted
48// import org.apache.log4j.Level;
49// import org.apache.log4j.Logger;
50// END android-deleted
51
52/**
53 * Log file wrapper class. Log messages into the message trace file and also write the log into
54 * the debug file if needed. This class keeps an XML formatted trace around for later access via
55 * RMI. The trace can be viewed with a trace viewer (see tools.traceviewerapp).
56 *
57 * @version 1.2 $Revision: 1.39 $ $Date: 2009/11/11 14:00:58 $
58 *
59 * @author M. Ranganathan <br/>
60 *
61 *
62 */
63public class ServerLog implements ServerLogger {
64
65    private boolean logContent;
66
67    protected StackLogger stackLogger;
68
69    /**
70     * Name of the log file in which the trace is written out (default is null)
71     */
72    private String logFileName;
73
74    /**
75     * Print writer that is used to write out the log file.
76     */
77    private PrintWriter printWriter;
78
79    /**
80     * Set auxililary information to log with this trace.
81     */
82    private String auxInfo;
83
84    private String description;
85
86    private String stackIpAddress;
87
88    private SIPTransactionStack sipStack;
89
90    private Properties configurationProperties;
91
92    public ServerLog() {
93        // Debug log file. Whatever gets logged by us also makes its way into debug log.
94    }
95
96    private void setProperties(Properties configurationProperties) {
97        this.configurationProperties = configurationProperties;
98        // Set a descriptive name for the message trace logger.
99        this.description = configurationProperties.getProperty("javax.sip.STACK_NAME");
100        this.stackIpAddress = configurationProperties.getProperty("javax.sip.IP_ADDRESS");
101        this.logFileName = configurationProperties.getProperty("gov.nist.javax.sip.SERVER_LOG");
102        String logLevel = configurationProperties.getProperty("gov.nist.javax.sip.TRACE_LEVEL");
103        String logContent = configurationProperties
104                .getProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT");
105
106        this.logContent = (logContent != null && logContent.equals("true"));
107
108        if (logLevel != null) {
109            if (logLevel.equals("LOG4J")) {
110                // if TRACE_LEVEL property is specified as
111                // "LOG4J" then, set the traceLevel based on
112                // the log4j effective log level.
113
114                // check whether a Log4j logger name has been
115                // specified. if not, use the stack name as the default
116                // logger name.
117
118                // BEGIN android-deleted
119                /*
120                Logger logger = Logger.getLogger(configurationProperties.getProperty(
121                        "gov.nist.javax.sip.LOG4J_LOGGER_NAME", this.description));
122                Level level = logger.getEffectiveLevel();
123                if (level == Level.OFF) {
124                    this.setTraceLevel(0);
125                } else if (level.isGreaterOrEqual(Level.DEBUG)) {
126                    this.setTraceLevel(TRACE_DEBUG);
127                } else if (level.isGreaterOrEqual(Level.INFO)) {
128                    this.setTraceLevel(TRACE_MESSAGES);
129                } else if (level.isGreaterOrEqual(Level.WARN)) {
130                    this.setTraceLevel(TRACE_EXCEPTION);
131                }
132                */
133                // END android-deleted
134            } else {
135                try {
136                    int ll;
137                    if (logLevel.equals("DEBUG")) {
138                        ll = TRACE_DEBUG;
139                    } else if (logLevel.equals("INFO")) {
140                        ll = TRACE_MESSAGES;
141                    } else if (logLevel.equals("ERROR")) {
142                        ll = TRACE_EXCEPTION;
143                    } else if (logLevel.equals("NONE") || logLevel.equals("OFF")) {
144                        ll = TRACE_NONE;
145                    } else {
146                        ll = Integer.parseInt(logLevel);
147                    }
148
149                    this.setTraceLevel(ll);
150                } catch (NumberFormatException ex) {
151                    System.out.println("ServerLog: WARNING Bad integer " + logLevel);
152                    System.out.println("logging dislabled ");
153                    this.setTraceLevel(0);
154                }
155            }
156        }
157        checkLogFile();
158
159    }
160
161    public void setStackIpAddress(String ipAddress) {
162        this.stackIpAddress = ipAddress;
163    }
164
165    // public static boolean isWebTesterCatchException=false;
166    // public static String webTesterLogFile=null;
167
168    /**
169     * default trace level
170     */
171    protected int traceLevel = TRACE_MESSAGES;
172
173    public synchronized void closeLogFile() {
174        if (printWriter != null) {
175            printWriter.close();
176            printWriter = null;
177        }
178    }
179
180    public void checkLogFile() {
181        if (logFileName == null || traceLevel < TRACE_MESSAGES) {
182            // Dont create a log file if tracing is
183            // disabled.
184            return;
185        }
186        try {
187            File logFile = new File(logFileName);
188            if (!logFile.exists()) {
189                logFile.createNewFile();
190                printWriter = null;
191            }
192            // Append buffer to the end of the file unless otherwise specified
193            // by the user.
194            if (printWriter == null) {
195                boolean overwrite = Boolean.valueOf(
196                    configurationProperties.getProperty(
197                        "gov.nist.javax.sip.SERVER_LOG_OVERWRITE"));
198
199                FileWriter fw = new FileWriter(logFileName, !overwrite);
200
201                printWriter = new PrintWriter(fw, true);
202                printWriter.println("<!-- "
203                        + "Use the  Trace Viewer in src/tools/tracesviewer to"
204                        + " view this  trace  \n"
205                        + "Here are the stack configuration properties \n"
206                        + "javax.sip.IP_ADDRESS= "
207                        + configurationProperties.getProperty("javax.sip.IP_ADDRESS") + "\n"
208                        + "javax.sip.STACK_NAME= "
209                        + configurationProperties.getProperty("javax.sip.STACK_NAME") + "\n"
210                        + "javax.sip.ROUTER_PATH= "
211                        + configurationProperties.getProperty("javax.sip.ROUTER_PATH") + "\n"
212                        + "javax.sip.OUTBOUND_PROXY= "
213                        + configurationProperties.getProperty("javax.sip.OUTBOUND_PROXY") + "\n"
214                        + "-->");
215                printWriter.println("<description\n logDescription=\"" + description
216                        + "\"\n name=\""
217                        + configurationProperties.getProperty("javax.sip.STACK_NAME")
218                        + "\"\n auxInfo=\"" + auxInfo + "\"/>\n ");
219                if (auxInfo != null) {
220
221                    if (sipStack.isLoggingEnabled()) {
222                        stackLogger
223                                .logDebug("Here are the stack configuration properties \n"
224                                        + "javax.sip.IP_ADDRESS= "
225                                        + configurationProperties
226                                                .getProperty("javax.sip.IP_ADDRESS")
227                                        + "\n"
228                                        + "javax.sip.ROUTER_PATH= "
229                                        + configurationProperties
230                                                .getProperty("javax.sip.ROUTER_PATH")
231                                        + "\n"
232                                        + "javax.sip.OUTBOUND_PROXY= "
233                                        + configurationProperties
234                                                .getProperty("javax.sip.OUTBOUND_PROXY")
235                                        + "\n"
236                                        + "gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS= "
237                                        + configurationProperties
238                                                .getProperty("gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS")
239                                        + "\n"
240                                        + "gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS= "
241                                        + configurationProperties
242                                                .getProperty("gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS")
243                                        + "\n"
244                                        + "gov.nist.javax.sip.REENTRANT_LISTENER= "
245                                        + configurationProperties
246                                                .getProperty("gov.nist.javax.sip.REENTRANT_LISTENER")
247                                        + "gov.nist.javax.sip.THREAD_POOL_SIZE= "
248                                        + configurationProperties
249                                                .getProperty("gov.nist.javax.sip.THREAD_POOL_SIZE")
250                                        + "\n");
251                        stackLogger.logDebug(" ]]> ");
252                        stackLogger.logDebug("</debug>");
253                        stackLogger.logDebug("<description\n logDescription=\"" + description
254                                + "\"\n name=\"" + stackIpAddress + "\"\n auxInfo=\"" + auxInfo
255                                + "\"/>\n ");
256                        stackLogger.logDebug("<debug>");
257                        stackLogger.logDebug("<![CDATA[ ");
258                    }
259                } else {
260
261                    if (sipStack.isLoggingEnabled()) {
262                        stackLogger.logDebug("Here are the stack configuration properties \n"
263                                + configurationProperties + "\n");
264                        stackLogger.logDebug(" ]]>");
265                        stackLogger.logDebug("</debug>");
266                        stackLogger.logDebug("<description\n logDescription=\"" + description
267                                + "\"\n name=\"" + stackIpAddress + "\" />\n");
268                        stackLogger.logDebug("<debug>");
269                        stackLogger.logDebug("<![CDATA[ ");
270                    }
271                }
272            }
273        } catch (IOException ex) {
274
275        }
276    }
277
278    /**
279     * Global check for whether to log or not. To minimize the time return false here.
280     *
281     * @return true -- if logging is globally enabled and false otherwise.
282     *
283     */
284    public boolean needsLogging() {
285        return logFileName != null;
286    }
287
288    /**
289     * Set the log file name
290     *
291     * @param name is the name of the log file to set.
292     */
293    public void setLogFileName(String name) {
294        logFileName = name;
295    }
296
297    /**
298     * return the name of the log file.
299     */
300    public String getLogFileName() {
301        return logFileName;
302    }
303
304    /**
305     * Log a message into the log file.
306     *
307     * @param message message to log into the log file.
308     */
309    private void logMessage(String message) {
310        // String tname = Thread.currentThread().getName();
311        checkLogFile();
312        String logInfo = message;
313        if (printWriter != null) {
314            printWriter.println(logInfo);
315        }
316        if (sipStack.isLoggingEnabled()) {
317            stackLogger.logInfo(logInfo);
318
319        }
320    }
321
322    private void logMessage(String message, String from, String to, boolean sender,
323            String callId, String firstLine, String status, String tid, long time,
324            long timestampVal) {
325
326        LogRecord log = this.sipStack.logRecordFactory.createLogRecord(message, from, to, time,
327                sender, firstLine, tid, callId, timestampVal);
328        if (log != null)
329            logMessage(log.toString());
330    }
331
332    /**
333     * Log a message into the log directory.
334     *
335     * @param message a SIPMessage to log
336     * @param from from header of the message to log into the log directory
337     * @param to to header of the message to log into the log directory
338     * @param sender is the server the sender
339     * @param time is the time to associate with the message.
340     */
341    public void logMessage(SIPMessage message, String from, String to, boolean sender, long time) {
342        checkLogFile();
343        if (message.getFirstLine() == null)
344            return;
345        CallID cid = (CallID) message.getCallId();
346        String callId = null;
347        if (cid != null)
348            callId = cid.getCallId();
349        String firstLine = message.getFirstLine().trim();
350        String inputText = (logContent ? message.encode() : message.encodeMessage());
351        String tid = message.getTransactionId();
352        TimeStampHeader tsHdr = (TimeStampHeader) message.getHeader(TimeStampHeader.NAME);
353        long tsval = tsHdr == null ? 0 : tsHdr.getTime();
354        logMessage(inputText, from, to, sender, callId, firstLine, null, tid, time, tsval);
355    }
356
357    /**
358     * Log a message into the log directory.
359     *
360     * @param message a SIPMessage to log
361     * @param from from header of the message to log into the log directory
362     * @param to to header of the message to log into the log directory
363     * @param status the status to log.
364     * @param sender is the server the sender or receiver (true if sender).
365     * @param time is the reception time.
366     */
367    public void logMessage(SIPMessage message, String from, String to, String status,
368            boolean sender, long time) {
369        checkLogFile();
370        CallID cid = (CallID) message.getCallId();
371        String callId = null;
372        if (cid != null)
373            callId = cid.getCallId();
374        String firstLine = message.getFirstLine().trim();
375        String encoded = (logContent ? message.encode() : message.encodeMessage());
376        String tid = message.getTransactionId();
377        TimeStampHeader tshdr = (TimeStampHeader) message.getHeader(TimeStampHeader.NAME);
378        long tsval = tshdr == null ? 0 : tshdr.getTime();
379        logMessage(encoded, from, to, sender, callId, firstLine, status, tid, time, tsval);
380    }
381
382    /**
383     * Log a message into the log directory. Time stamp associated with the message is the current
384     * time.
385     *
386     * @param message a SIPMessage to log
387     * @param from from header of the message to log into the log directory
388     * @param to to header of the message to log into the log directory
389     * @param status the status to log.
390     * @param sender is the server the sender or receiver (true if sender).
391     */
392    public void logMessage(SIPMessage message, String from, String to, String status,
393            boolean sender) {
394        logMessage(message, from, to, status, sender, System.currentTimeMillis());
395    }
396
397    /**
398     * Log an exception stack trace.
399     *
400     * @param ex Exception to log into the log file
401     */
402
403    public void logException(Exception ex) {
404        if (traceLevel >= TRACE_EXCEPTION) {
405            checkLogFile();
406            ex.printStackTrace();
407            if (printWriter != null)
408                ex.printStackTrace(printWriter);
409
410        }
411    }
412
413    /**
414     * Set the trace level for the stack.
415     *
416     * @param level -- the trace level to set. The following trace levels are supported:
417     *        <ul>
418     *        <li> 0 -- no tracing </li>
419     *
420     * <li> 16 -- trace messages only </li>
421     *
422     * <li> 32 Full tracing including debug messages. </li>
423     *
424     * </ul>
425     */
426    public void setTraceLevel(int level) {
427        traceLevel = level;
428    }
429
430    /**
431     * Get the trace level for the stack.
432     *
433     * @return the trace level
434     */
435    public int getTraceLevel() {
436        return traceLevel;
437    }
438
439    /**
440     * Set aux information. Auxiliary information may be associated with the log file. This is
441     * useful for remote logs.
442     *
443     * @param auxInfo -- auxiliary information.
444     */
445    public void setAuxInfo(String auxInfo) {
446        this.auxInfo = auxInfo;
447    }
448
449	public void setSipStack(SipStack sipStack) {
450		if(sipStack instanceof SIPTransactionStack) {
451			this.sipStack = (SIPTransactionStack)sipStack;
452	        this.stackLogger = this.sipStack.getStackLogger();
453		}
454		else
455			throw new IllegalArgumentException("sipStack must be a SIPTransactionStack");
456	}
457
458	public void setStackProperties(Properties stackProperties) {
459		setProperties(stackProperties);
460	}
461
462	public void setLevel(int jsipLoggingLevel) {
463
464	}
465
466}
467