summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authoreea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1997-07-25 20:42:38 +0000
committereea1 <eea1@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1997-07-25 20:42:38 +0000
commitd4bee2e56bc3108a6e1aa960fddc37ef4495ee33 (patch)
treea94250e5ed5a3f9af1d02558c2582517c8aef88f /java
parent8df8bff2c8082791128c443b06a72b60486a6259 (diff)
downloadATCD-d4bee2e56bc3108a6e1aa960fddc37ef4495ee33.tar.gz
This is the first version of the JACE Server Logging service. It
is based heavily on the example written by Chris Cleeland, and it should be compatible with the C++ ACE version. The Client Logging service isn't necessary in Java since applications have to use sockets to communicate with the services anyway (the C++ version let apps communicate with the middle-man Client Logging Service via named pipes).
Diffstat (limited to 'java')
-rw-r--r--java/netsvcs/Logger/LogMessageReceiver.java43
-rw-r--r--java/netsvcs/Logger/LogRecord.java185
-rw-r--r--java/netsvcs/Logger/LoggerTest.java112
-rw-r--r--java/netsvcs/Logger/ServerLoggingAcceptor.java157
-rw-r--r--java/netsvcs/Logger/ServerLoggingHandler.java112
5 files changed, 609 insertions, 0 deletions
diff --git a/java/netsvcs/Logger/LogMessageReceiver.java b/java/netsvcs/Logger/LogMessageReceiver.java
new file mode 100644
index 00000000000..a2e6df9fba5
--- /dev/null
+++ b/java/netsvcs/Logger/LogMessageReceiver.java
@@ -0,0 +1,43 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Logger
+ *
+ * = FILENAME
+ * LogMessageReceiver.java
+ *
+ *@author Everett Anderson
+ *
+ *************************************************/
+package netsvcs.Logger;
+
+import java.lang.*;
+import java.io.*;
+import netsvcs.Logger.LogRecord;
+
+/**
+ *
+ * <p><h2>DESCRIPTION</h2>
+ *
+ * <blockquote>
+ * The LogMessageReceiver removes the code that handles a log message from
+ * the logging service acceptor. The DefaultLMR simply calls the LogRecord's
+ * print method. Other implementations of this interface can be built and
+ * given to the ServerLoggingAcceptor to change the result.
+ *
+ * @see netsvcs.Logger.ServerLoggingAcceptor, netsvcs.Logger.LogRecord
+ */
+public interface LogMessageReceiver
+{
+ public void logRecord (String hostname,
+ LogRecord record);
+};
+
+class DefaultLMR implements LogMessageReceiver
+{
+ public void logRecord (String hostname,
+ LogRecord record)
+ {
+ record.print(hostname, true, System.err);
+ }
+}
diff --git a/java/netsvcs/Logger/LogRecord.java b/java/netsvcs/Logger/LogRecord.java
new file mode 100644
index 00000000000..721341cb252
--- /dev/null
+++ b/java/netsvcs/Logger/LogRecord.java
@@ -0,0 +1,185 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Logger
+ *
+ * = FILENAME
+ * LogRecord.java
+ *
+ *@author Chris Cleeland, Everett Anderson
+ *
+ *************************************************/
+package netsvcs.Logger;
+
+import java.util.Date;
+import java.io.DataOutputStream;
+import java.io.DataInputStream;
+import java.io.PrintStream;
+import java.io.IOException;
+import JACE.OS.*;
+
+/**
+ *
+ * <p><h2>DESCRIPTION</h2>
+ *
+ * <blockquote>
+ * Communicates logging information. Compatible with the C++ ACE
+ * ACE_Log_Record class.
+ *
+ */
+public class LogRecord
+{
+ final public int MAXLOGMSGLEN = 4 * 1024;
+
+ private int type_;
+ private int length_;
+ private long msec_;
+ private int pid_;
+ private byte[] msgData_;
+ private final static int numIntMembers = 5;
+ private final static int sizeofIntInBytes = 4;
+
+ /**
+ * Create a default instance.
+ */
+ public LogRecord()
+ {
+ this(0, (int)new Date().getTime(), 0);
+ }
+
+ /**
+ * Create a LogRecord. This is the designated initializer.
+ * @param priority a numeric specification of the priority (ascending)
+ * @param milliseconds time attached to the log entry in Unix <pre>time_t</pre> format
+ * @param pid the process ID; not currently used
+ */
+ public LogRecord(int priority,
+ long milliseconds,
+ int pid)
+ {
+ type(priority);
+ timeStamp(milliseconds);
+ length(0);
+ pid(pid);
+ }
+
+ /**
+ * Conversion to string. Only includes the <pre>msgData_</pre> member.
+ */
+ public String toString()
+ {
+ return new String(msgData_);
+ }
+
+ /**
+ * Place a textual representation of the record on a PrintStream.
+ * @param hostname name of the host generating this record
+ * @param verbose if <b>true</b>, print information in the form, (give example)
+ * @param ps A PrintStream instance to which the output should go.
+ * @see PrintStream,String
+ */
+ public void print(String hostname,
+ boolean verbose,
+ PrintStream ps)
+ {
+ String toprint;
+ if (verbose)
+ {
+ Date now = new Date(this.timeStamp());
+
+ /* 01234567890123456789012345 */
+ /* Wed Oct 18 14:25:36 1989n0 */
+ toprint = now.toString().substring(4) + "@"
+ + hostname + "@" + pid_ + "@" + type_ + "@"
+ + this.toString();
+ }
+ else
+ {
+ toprint = this.toString();
+ }
+ ps.println(toprint);
+ }
+
+ /**
+ * Streaming methods
+ */
+ public void streamInFrom(DataInputStream dis) throws IOException
+ {
+ // Order here must match layout order in the C++ class.
+ // This, of course, is VERY fragile, and ought not be used as
+ // a model for anything except how NOT to do anything.
+ type(dis.readInt());
+ length(dis.readInt());
+ this.timeStamp((long)dis.readInt() * 1000);
+
+ // Skip smaller time resolution info since we're lucky if Java's
+ // timer can handle more than millisecond precision, anyway
+ dis.skipBytes(4);
+
+ pid(dis.readInt());
+
+ // Does readFully() allocate space for the buffer? Either
+ // way, we won't have memory leaks :-)
+ int dataLength = (int) (length_ - numIntMembers * sizeofIntInBytes);
+ msgData_ = new byte[dataLength];
+ dis.readFully(msgData_, 0, dataLength);
+ }
+
+ public void streamOutTo(DataOutputStream dos) throws IOException
+ {
+ dos.writeInt(length());
+ dos.writeInt(type());
+ dos.writeInt(length());
+ dos.writeInt((int)(this.msec_ / 1000));
+ dos.writeInt(0);
+ dos.writeInt(pid());
+
+ dos.write(msgData_);
+ }
+
+ /**
+ * Accessor methods
+ */
+ public int type() { return type_; }
+ public void type(int t) { type_ = t; }
+
+ public int length() { return length_; }
+ public void length(int l) { length_ = l; }
+ private void setLen(int msgLen)
+ { length(msgLen + numIntMembers * sizeofIntInBytes); }
+
+ public long timeStamp() { return this.msec_; }
+ public void timeStamp(long msec){ this.msec_ = msec; }
+
+ public int pid() { return pid_; }
+ public void pid(int p) { pid_ = p; }
+
+ public byte[] msgData() { return msgData_; }
+ public void msgData(byte[] m)
+ {
+ int size = m.length;
+
+ if (size > MAXLOGMSGLEN)
+ size = MAXLOGMSGLEN;
+
+ this.msgData_ = new byte[size];
+
+ System.arraycopy(m, 0, msgData_, 0, size);
+
+ setLen(size);
+ }
+
+ public void msgData(String m)
+ {
+ byte temp[] = m.getBytes();
+ if (temp.length > MAXLOGMSGLEN) {
+ this.msgData_ = new byte[MAXLOGMSGLEN];
+
+ System.arraycopy(temp, 0, msgData_, 0, MAXLOGMSGLEN);
+ } else
+ this.msgData_ = temp;
+
+ setLen(msgData_.length);
+ }
+};
+
diff --git a/java/netsvcs/Logger/LoggerTest.java b/java/netsvcs/Logger/LoggerTest.java
new file mode 100644
index 00000000000..52a952ce5ee
--- /dev/null
+++ b/java/netsvcs/Logger/LoggerTest.java
@@ -0,0 +1,112 @@
+/*************************************************
+ *
+ * = FILENAME
+ * LoggerTest.java
+ *
+ *@author Everett Anderson
+ *
+ *************************************************/
+import JACE.SOCK_SAP.*;
+import java.io.*;
+import java.net.*;
+import JACE.OS.*;
+import netsvcs.Logger.LogRecord;
+
+/**
+ *
+ * <p><h2>DESCRIPTION</h2>
+ *
+ * <blockquote>
+ * This is an example/test log client very similar to the direct_logging client of
+ * C++ ACE. The server logging service should correctly receive messages from both
+ * of these examples.
+ * </blockquote>
+ *
+ * @see netsvcs.Logger.ServerLoggingAcceptor, netsvcs.Logger.LogRecord
+ */
+public class LoggerTest {
+
+ // Command line: <port> <hostname>
+ //
+ // Creates a "hello world" log message and sends it to the server logging service.
+ // If no command line arguments are given, it uses ACE.DEFAULT_SERVER_PORT, and the
+ // current machine for the service location.
+ //
+ public static void main(String args[])
+ {
+ int port = args.length > 0 ? (new Integer(args[0])).intValue() : ACE.DEFAULT_SERVER_PORT;
+
+ SOCKStream cli_stream = new SOCKStream();
+ INETAddr remote_addr;
+ String host;
+
+ try {
+
+ host = args.length > 1 ? args[1] : InetAddress.getLocalHost().getHostName();
+
+ remote_addr = new INETAddr(port, host)
+;
+ } catch (UnknownHostException uhe) {
+ ACE.ERROR("UnknownHostException " + uhe);
+ return;
+ }
+
+ System.out.println("Connecting to " + host + " on port " + port);
+
+ SOCKConnector con = new SOCKConnector();
+
+ try {
+
+ // Connect to the service
+ con.connect(cli_stream, remote_addr);
+
+ } catch (SocketException se) {
+
+ ACE.ERROR("Socket Exception " + se);
+ return;
+
+ } catch (IOException ie) {
+
+ ACE.ERROR("IOException " + ie);
+ return;
+ }
+
+
+ // Send a message with priority 4, the current time,
+ // and 0 for the process ID.
+ LogRecord record = new LogRecord(4,
+ System.currentTimeMillis(),
+ 0);
+
+ // Set the message
+ record.msgData("hello world");
+
+ try {
+
+ // Get a transmission system from the socket
+ OutputStream os = cli_stream.socket().getOutputStream();
+ DataOutputStream dos = new DataOutputStream(os);
+
+ // Send it
+ record.streamOutTo(dos);
+
+ // Close the socket
+ cli_stream.close();
+
+ } catch (IOException ie) {
+
+ ACE.ERROR("IOException, loop: " + ie);
+ return;
+ }
+ }
+};
+
+
+
+
+
+
+
+
+
+
diff --git a/java/netsvcs/Logger/ServerLoggingAcceptor.java b/java/netsvcs/Logger/ServerLoggingAcceptor.java
new file mode 100644
index 00000000000..c68c089a0f7
--- /dev/null
+++ b/java/netsvcs/Logger/ServerLoggingAcceptor.java
@@ -0,0 +1,157 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Logger
+ *
+ * = FILENAME
+ * ServerLoggingAcceptor.java
+ *
+ *@author Chris Cleeland, Everett Anderson
+ *
+ *************************************************/
+package netsvcs.Logger;
+
+import JACE.SOCK_SAP.*;
+import JACE.Connection.*;
+import netsvcs.Logger.*;
+import JACE.OS.*;
+import java.io.*;
+import java.net.*;
+import JACE.Misc.*;
+
+/**
+ *
+ * <p><h2>DESCRIPTION</h2>
+ *
+ * <blockquote>
+ * Acceptor: Listens on a specified port and launches ServerLoggingHandlers
+ * in response to requests. A LogMessageReceiver can be specified on the
+ * command line to change the way the logging service processes messages.
+ *
+ * @see netsvcs.Logger.ServerLoggingHandler, netsvcs.Logger.LogMessageReceiver
+ */
+public class ServerLoggingAcceptor extends Acceptor implements Runnable
+{
+ // Main function so the service can be started without the service
+ // configurator.
+ public static void main (String [] args)
+ {
+ ServerLoggingAcceptor sla = new ServerLoggingAcceptor();
+
+ sla.init(args);
+ }
+
+ // Called by the service configurator, receives the command line and
+ // launches its own thread.
+ public int init (String [] args)
+ {
+ this.parseArgs(args);
+
+ // *** should contain choices like what the default is
+ // in an options singleton?
+ if (this.receiver_ == null)
+ this.receiver_ = new DefaultLMR();
+
+ new Thread (this).start();
+ return 0;
+ }
+
+ // Specify what LogMessageReceiver to use
+ public void setLMR(LogMessageReceiver receiver)
+ {
+ this.receiver_ = receiver;
+ }
+
+ // Accessor for the LogMessageReceiver
+ public LogMessageReceiver getLMR ()
+ {
+ return this.receiver_;
+ }
+
+ // Create a new ServerLoggingHandler
+ protected SvcHandler makeSvcHandler ()
+ throws InstantiationException, IllegalAccessException
+ {
+ // ** could contain this choice in a singleton, too
+ return new netsvcs.Logger.ServerLoggingHandler (this.receiver_);
+ }
+
+ // Run forever accepting new connections
+ public void run ()
+ {
+ try {
+
+ this.open (this.port_);
+ while (true)
+ this.accept(); // blocks
+
+ } catch (SocketException e)
+ {
+ ACE.ERROR ("Socket Exception: " + e);
+ }
+ catch (InstantiationException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (IllegalAccessException e)
+ {
+ ACE.ERROR (e);
+ }
+ catch (IOException e)
+ {
+ ACE.ERROR (e);
+ }
+
+ ACE.ERROR("ServerLoggingAcceptor has exited");
+ }
+
+ // Process the command line
+ protected void parseArgs (String args[])
+ {
+ String s;
+ GetOpt opt = new GetOpt (args, "p:r:");
+ for (int c; (c = opt.next ()) != -1; )
+ {
+ switch (c)
+ {
+ case 'p':
+ s = opt.optarg ();
+ this.port_ = (new Integer (s)).intValue ();
+ break;
+ case 'r':
+ // Load the LMR with the given name
+ s = new String(opt.optarg ());
+ Class LMRfactory;
+ try {
+ LMRfactory = Class.forName(s);
+
+ receiver_ = (LogMessageReceiver)LMRfactory.newInstance();
+
+ } catch (ClassNotFoundException e) {
+ ACE.ERROR("Unable to find LMR factory: " + e);
+ } catch (InstantiationException e) {
+ ACE.ERROR("Creating LMR: " + e);
+ } catch (IllegalAccessException e) {
+ ACE.ERROR("Creating LMR: " + e);
+ }
+ // Any of the above exceptions will result in just using the
+ // default LMR
+ break;
+ default:
+ ACE.ERROR ("Unknown argument: " + c);
+ ACE.ERROR ("Valid args: -p <port> -r <LogMessageReceiver name>");
+ break;
+ }
+ }
+ }
+
+ // port should be in options singleton **
+ private int port_ = ACE.DEFAULT_SERVER_PORT;
+ private LogMessageReceiver receiver_ = null;
+};
+
+
+
+
+
+
diff --git a/java/netsvcs/Logger/ServerLoggingHandler.java b/java/netsvcs/Logger/ServerLoggingHandler.java
new file mode 100644
index 00000000000..c8a364526cc
--- /dev/null
+++ b/java/netsvcs/Logger/ServerLoggingHandler.java
@@ -0,0 +1,112 @@
+/*************************************************
+ *
+ * = PACKAGE
+ * netsvcs.Logger
+ *
+ * = FILENAME
+ * ServerLoggingHandler.java
+ *
+ *@author Chris Cleeland, Everett Anderson
+ *
+ *************************************************/
+package netsvcs.Logger;
+
+import JACE.SOCK_SAP.*;
+import JACE.Connection.*;
+import JACE.OS.*;
+import java.util.*;
+import java.io.*;
+
+/**
+ *
+ * <p><h2>DESCRIPTION</h2>
+ *
+ * <blockquote>
+ * Created by ServerLoggingAcceptor every time a client connects. This reads
+ * a logging statement passes it to the LogMessageReceiver for processing.
+ * </blockquote>
+ *
+ * @see netsvcs.Logger.ServerLoggingAcceptor
+ */
+public class ServerLoggingHandler extends SvcHandler
+{
+ // Processes log messages
+ private LogMessageReceiver receiver_;
+
+ // Constructor
+ public ServerLoggingHandler (LogMessageReceiver receiver)
+ {
+ super();
+ this.receiver_ = receiver;
+ }
+
+ // Start this handler in its own thread
+ public int open(Object obj)
+ {
+ new Thread (this).start();
+ return 0;
+ }
+
+ // Accessor: get the host name of the connected client
+ protected String hostName ()
+ {
+ return new String(this.stream_.socket().getInetAddress().getHostName());
+ }
+
+ // Receive input from the client, and send it to the LMR
+ public void run()
+ {
+ DataInputStream dis = (DataInputStream) this.stream_.inputStream();
+
+ for (;;)
+ {
+ // Messages arrive in the following format:
+ // o 4 byte length (network format)
+ // o message, in ACE.LogRecord format
+ //
+ // Hey! We need exception catching in here too!
+ try
+ {
+ // Reconstitute a log message from the wire
+ LogRecord rec = new LogRecord();
+
+ // We don't really need this, because
+ // the object already knows how to
+ // extract itself properly. However,
+ // in order to interoperate with the
+ // C++ version, this must be extracted.
+ // Plus, it makes a convenient way to
+ // check everything.
+ int length = dis.readInt();
+
+ rec.streamInFrom(dis);
+
+ if (rec.length() == length)
+ {
+ // Give the record to the log processor
+ this.receiver_.logRecord(this.hostName(),
+ rec);
+ }
+ else
+ {
+ ACE.ERROR(Thread.currentThread().getName() + ": Length error");
+ }
+ }
+ catch (EOFException eof)
+ {
+ try {
+ this.stream_.close();
+ } catch (IOException n) { }
+
+ return;
+ }
+ catch (IOException ioe)
+ {
+ ACE.ERROR(Thread.currentThread().getName()
+ + ": "
+ + ioe);
+ }
+ }
+ }
+};
+