Project

General

Profile

1 2096 jones
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2004 Regents of the University of California and the
4
 *             National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author$'
7
 *     '$Date$'
8
 * '$Revision$'
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
 */
24
package edu.ucsb.nceas.metacat;
25
26 2104 jones
import java.sql.PreparedStatement;
27 2111 jones
import java.sql.ResultSet;
28 2096 jones
import java.sql.SQLException;
29 2104 jones
import java.sql.Timestamp;
30 6595 leinfelder
import java.util.ArrayList;
31 2096 jones
import java.util.Date;
32 6595 leinfelder
import java.util.List;
33 7285 leinfelder
import java.util.Vector;
34 2096 jones
35 2663 sgarg
import org.apache.log4j.Logger;
36 7285 leinfelder
import org.dataone.service.types.v1.Event;
37
import org.dataone.service.types.v1.Identifier;
38
import org.dataone.service.types.v1.Log;
39
import org.dataone.service.types.v1.LogEntry;
40
import org.dataone.service.types.v1.NodeReference;
41
import org.dataone.service.types.v1.Subject;
42 6944 leinfelder
import org.dataone.service.util.DateTimeMarshaller;
43 2663 sgarg
44 5015 daigle
import edu.ucsb.nceas.metacat.database.DBConnection;
45
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
46 7437 leinfelder
import edu.ucsb.nceas.metacat.database.DatabaseService;
47 7285 leinfelder
import edu.ucsb.nceas.metacat.properties.PropertyService;
48 7409 leinfelder
import edu.ucsb.nceas.metacat.util.DocumentUtil;
49 7285 leinfelder
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
50 5015 daigle
51 2096 jones
/**
52
 * EventLog is used to intialize and store a log of events that occur in an
53
 * application. The events are registered with the logger as they occur, but
54
 * EventLog writes them to permenant storage when it is most convenient or
55
 * efficient. EventLog is a Singleton as there should always be only one object
56
 * for these logging events.
57
 *
58
 * TODO: Logging to the database needn't be synchronous with the event.
59
 * Instead, a separate thread can be launched that periodically sleeps and only
60
 * wakes periodically to see if metacat is idle.  The log event can be cached
61
 * and inserted later when the thread wakes and finds metacat idle.
62
 *
63
 * TODO: Write a function that archives a part of the log table to an
64
 * external text file so that the log table doesn't get to big.  This
65
 * function should be able to be called manually or on a schedule.
66
 *
67
 * TODO: Write an access function that returns an XML report for a
68
 * specific subset of events.  Users should be able to query on
69
 * principal, docid/rev, date, event, and possibly other fields.
70
 *
71
 * @author jones
72
 */
73
public class EventLog
74
{
75
    /**
76
     * The single instance of the event log that is always returned.
77
     */
78
    private static EventLog self = null;
79 2663 sgarg
    private Logger logMetacat = Logger.getLogger(EventLog.class);
80 2096 jones
81
    /**
82
     * A private constructor that initializes the class when getInstance() is
83
     * called.
84
     */
85
    private EventLog()
86
    {
87
    }
88
89
    /**
90
     * Return the single instance of the event log after initializing it if it
91
     * wasn't previously initialized.
92
     *
93
     * @return the single EventLog instance
94
     */
95
    public static EventLog getInstance()
96
    {
97
        if (self == null) {
98
            self = new EventLog();
99
        }
100
        return self;
101
    }
102
103
    /**
104
     * Log an event of interest to the application. The information logged can
105
     * include basic identification information about the principal or computer
106
     * that initiated the event.
107
     *
108 2099 jones
     * @param ipAddress the internet protocol address for the event
109 6542 leinfelder
     * @param userAgent the agent making the request
110 2099 jones
	 * @param principal the principal for the event (a username, etc)
111
	 * @param docid the identifier of the document to which the event applies
112
	 * @param event the string code for the event
113 2096 jones
     */
114 6542 leinfelder
    public void log(String ipAddress, String userAgent, String principal, String docid, String event) {
115
        EventLogData logData = new EventLogData(ipAddress, principal, docid, event);
116 2096 jones
        insertLogEntry(logData);
117
    }
118 2099 jones
119 2096 jones
    /**
120
     * Insert a single log event record to the database.
121
     *
122
     * @param logData the data to be logged when an event occurs
123
     */
124
    private void insertLogEntry(EventLogData logData)
125
    {
126
        String insertString = "insert into access_log"
127 6542 leinfelder
                + "(ip_address, user_agent, principal, docid, "
128 2096 jones
                + "event, date_logged) "
129 6595 leinfelder
                + "values ( ?, ?, ?, ?, ?, ? )";
130
131 2096 jones
        DBConnection dbConn = null;
132
        int serialNumber = -1;
133
        try {
134
            // Get a database connection from the pool
135 2111 jones
            dbConn = DBConnectionPool.getDBConnection("EventLog.insertLogEntry");
136 2096 jones
            serialNumber = dbConn.getCheckOutSerialNumber();
137
138
            // Execute the insert statement
139 2104 jones
            PreparedStatement stmt = dbConn.prepareStatement(insertString);
140 6595 leinfelder
141
            stmt.setString(1, logData.getIpAddress());
142
            stmt.setString(2, logData.getUserAgent());
143
            stmt.setString(3, logData.getPrincipal());
144
            stmt.setString(4, logData.getDocid());
145
            stmt.setString(5, logData.getEvent());
146
            stmt.setTimestamp(6, new Timestamp(new Date().getTime()));
147 2104 jones
            stmt.executeUpdate();
148 2096 jones
            stmt.close();
149
        } catch (SQLException e) {
150 2663 sgarg
        	logMetacat.error("Error while logging event to database: "
151
                    + e.getMessage());
152 2096 jones
        } finally {
153
            // Return database connection to the pool
154
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
155
        }
156
    }
157 2110 jones
158
    /**
159
     * Get a report of the log events that match a set of filters.  The
160 2111 jones
     * filter parameters can be null; log records are subset based on
161 2110 jones
     * non-null filter parameters.
162
     *
163
     * @param ipAddress the internet protocol address for the event
164
	 * @param principal the principal for the event (a username, etc)
165
	 * @param docid the identifier of the document to which the event applies
166
	 * @param event the string code for the event
167 2111 jones
	 * @param startDate beginning of date range for query
168
	 * @param endDate end of date range for query
169
	 * @return an XML-formatted report of the access log entries
170 2110 jones
     */
171 2111 jones
    public String getReport(String[] ipAddress, String[] principal, String[] docid,
172 5693 leinfelder
            String[] event, Timestamp startDate, Timestamp endDate, boolean anonymous)
173 2110 jones
    {
174 2111 jones
        StringBuffer resultDoc = new StringBuffer();
175
        StringBuffer query = new StringBuffer();
176 6542 leinfelder
        query.append("select entryid, ip_address, user_agent, principal, docid, "
177 2111 jones
            + "event, date_logged from access_log");
178
//                        + ""
179
//                        + "event, date_logged) " + "values (" + "'"
180
//                        + logData.getIpAddress() + "', " + "'"
181
//                        + logData.getPrincipal() + "', " + "'"
182
//                        + logData.getDocid() + "', " + "'" + logData.getEvent()
183
//                        + "', " + " ? " + ")";
184
        if (ipAddress != null || principal != null || docid != null
185
                        || event != null || startDate != null || endDate != null) {
186
            query.append(" where ");
187
        }
188
        boolean clauseAdded = false;
189
        int startIndex = 0;
190
        int endIndex = 0;
191
192 6595 leinfelder
        List<String> paramValues = new ArrayList<String>();
193 2111 jones
        if (ipAddress != null) {
194 6595 leinfelder
        	query.append("ip_address in (");
195
        	for (int i = 0; i < ipAddress.length; i++) {
196
        		if (i > 0) {
197
            		query.append(", ");
198
        		}
199
        		query.append("?");
200
        		paramValues.add(ipAddress[i]);
201
        	}
202
        	query.append(") ");
203 2111 jones
            clauseAdded = true;
204
        }
205
        if (principal != null) {
206 7309 leinfelder
        	if (clauseAdded) {
207
                query.append(" and ");
208
            }
209 6595 leinfelder
        	query.append("principal in (");
210
        	for (int i = 0; i < principal.length; i++) {
211
        		if (i > 0) {
212
            		query.append(", ");
213
        		}
214
        		query.append("?");
215
        		paramValues.add(principal[i]);
216
        	}
217
        	query.append(") ");
218 2111 jones
            clauseAdded = true;
219
        }
220
        if (docid != null) {
221 7309 leinfelder
        	if (clauseAdded) {
222
                query.append(" and ");
223
            }
224 6595 leinfelder
        	query.append("docid in (");
225
        	for (int i = 0; i < docid.length; i++) {
226
        		if (i > 0) {
227
            		query.append(", ");
228
        		}
229
        		query.append("?");
230 7409 leinfelder
        		String fullDocid = docid[i];
231
        		// allow docid without revision - look up latest version
232
        		try {
233
        			fullDocid = DocumentUtil.appendRev(fullDocid);
234
        		} catch (Exception e) {
235
					// just warn about this
236
        			logMetacat.warn("Could not check docid for revision: " + fullDocid, e);
237
				}
238
        		paramValues.add(fullDocid);
239 6595 leinfelder
        	}
240
        	query.append(") ");
241 2111 jones
            clauseAdded = true;
242
        }
243
        if (event != null) {
244 7309 leinfelder
        	if (clauseAdded) {
245
                query.append(" and ");
246
            }
247 6595 leinfelder
        	query.append("event in (");
248
        	for (int i = 0; i < event.length; i++) {
249
        		if (i > 0) {
250
            		query.append(", ");
251
        		}
252
        		query.append("?");
253
        		paramValues.add(event[i]);
254
        	}
255
        	query.append(") ");
256 2111 jones
            clauseAdded = true;
257
        }
258
        if (startDate != null) {
259
            if (clauseAdded) {
260
                query.append(" and ");
261
            }
262 7057 leinfelder
            query.append("date_logged >= ?");
263 2111 jones
            clauseAdded = true;
264
            startIndex++;
265
        }
266
        if (endDate != null) {
267
            if (clauseAdded) {
268
                query.append(" and ");
269
            }
270
            query.append("date_logged < ?");
271
            clauseAdded = true;
272
            endIndex = startIndex + 1;
273
        }
274
        DBConnection dbConn = null;
275
        int serialNumber = -1;
276
        try {
277
            // Get a database connection from the pool
278
            dbConn = DBConnectionPool.getDBConnection("EventLog.getReport");
279
            serialNumber = dbConn.getCheckOutSerialNumber();
280
281 2113 jones
            // Execute the query statement
282 2111 jones
            PreparedStatement stmt = dbConn.prepareStatement(query.toString());
283 6595 leinfelder
            //set the param values
284
            int parameterIndex = 1;
285
            for (String val: paramValues) {
286 7309 leinfelder
            	stmt.setString(parameterIndex++, val);
287 6595 leinfelder
            }
288 6598 leinfelder
            if (startDate != null) {
289
                stmt.setTimestamp(parameterIndex++, startDate);
290 2111 jones
            }
291 6598 leinfelder
            if (endDate != null) {
292
            	stmt.setTimestamp(parameterIndex++, endDate);
293 2111 jones
            }
294
            stmt.execute();
295
            ResultSet rs = stmt.getResultSet();
296 2113 jones
            //process the result and return it as an XML document
297 2111 jones
            resultDoc.append("<?xml version=\"1.0\"?>\n");
298
            resultDoc.append("<log>\n");
299
            while (rs.next()) {
300 5693 leinfelder
                resultDoc.append(
301
                		generateXmlRecord(
302
                				rs.getString(1), //id
303
                				anonymous ? "" : rs.getString(2), //ip
304 6542 leinfelder
                				rs.getString(3), //userAgent
305
                				anonymous ? "" : rs.getString(4), //principal
306 5693 leinfelder
                                rs.getString(5),
307 6542 leinfelder
                                rs.getString(6),
308
                                rs.getTimestamp(7)));
309 2111 jones
            }
310
            resultDoc.append("</log>");
311
            stmt.close();
312
        } catch (SQLException e) {
313 2663 sgarg
        	logMetacat.info("Error while logging event to database: "
314
                            + e.getMessage());
315 2111 jones
        } finally {
316
            // Return database connection to the pool
317
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
318
        }
319
        return resultDoc.toString();
320 2110 jones
    }
321 2111 jones
322 7285 leinfelder
323
324
    public Log getD1Report(String[] ipAddress, String[] principal, String[] docid,
325
            Event event, Timestamp startDate, Timestamp endDate, boolean anonymous, Integer start, Integer count)
326
    {
327
328
        Log log = new Log();
329
330
    	NodeReference memberNode = new NodeReference();
331
        String nodeId = "localhost";
332
        try {
333
            nodeId = PropertyService.getProperty("dataone.nodeId");
334
        } catch (PropertyNotFoundException e1) {
335
            // TODO Auto-generated catch block
336
            e1.printStackTrace();
337
        }
338
        memberNode.setValue(nodeId);
339
340 7451 leinfelder
        String countClause = "select count(*) ";
341
        String fieldsClause = "select " +
342 7285 leinfelder
        		"entryid, " +
343
        		"id.guid as identifier, " +
344
        		"ip_address, " +
345
        		"user_agent, " +
346
        		"principal, " +
347
        		"case " +
348
        		"	when event = 'insert' then 'create' " +
349
        		"	else event " +
350
        		"end as event, " +
351 7451 leinfelder
        		"date_logged ";
352
353
        StringBuffer queryWhereClause = new StringBuffer();
354
        queryWhereClause.append(
355 7285 leinfelder
        		"from access_log al, identifier id " +
356
        		"where al.docid = id.docid||'.'||id.rev "
357
        );
358
359 7287 leinfelder
        boolean clauseAdded = true;
360 7285 leinfelder
361
        List<String> paramValues = new ArrayList<String>();
362
        if (ipAddress != null) {
363 7309 leinfelder
        	if (clauseAdded) {
364 7451 leinfelder
                queryWhereClause.append(" and ");
365 7309 leinfelder
            }
366 7451 leinfelder
        	queryWhereClause.append("ip_address in (");
367 7285 leinfelder
        	for (int i = 0; i < ipAddress.length; i++) {
368
        		if (i > 0) {
369 7451 leinfelder
            		queryWhereClause.append(", ");
370 7285 leinfelder
        		}
371 7451 leinfelder
        		queryWhereClause.append("?");
372 7285 leinfelder
        		paramValues.add(ipAddress[i]);
373
        	}
374 7451 leinfelder
        	queryWhereClause.append(") ");
375 7285 leinfelder
            clauseAdded = true;
376
        }
377
        if (principal != null) {
378 7309 leinfelder
        	if (clauseAdded) {
379 7451 leinfelder
                queryWhereClause.append(" and ");
380 7309 leinfelder
            }
381 7451 leinfelder
        	queryWhereClause.append("principal in (");
382 7285 leinfelder
        	for (int i = 0; i < principal.length; i++) {
383
        		if (i > 0) {
384 7451 leinfelder
            		queryWhereClause.append(", ");
385 7285 leinfelder
        		}
386 7451 leinfelder
        		queryWhereClause.append("?");
387 7285 leinfelder
        		paramValues.add(principal[i]);
388
        	}
389 7451 leinfelder
        	queryWhereClause.append(") ");
390 7285 leinfelder
            clauseAdded = true;
391
        }
392
        if (docid != null) {
393 7309 leinfelder
        	if (clauseAdded) {
394 7451 leinfelder
                queryWhereClause.append(" and ");
395 7309 leinfelder
            }
396 7451 leinfelder
        	queryWhereClause.append("al.docid in (");
397 7285 leinfelder
        	for (int i = 0; i < docid.length; i++) {
398
        		if (i > 0) {
399 7451 leinfelder
            		queryWhereClause.append(", ");
400 7285 leinfelder
        		}
401 7451 leinfelder
        		queryWhereClause.append("?");
402 7285 leinfelder
        		paramValues.add(docid[i]);
403
        	}
404 7451 leinfelder
        	queryWhereClause.append(") ");
405 7285 leinfelder
            clauseAdded = true;
406
        }
407
        if (event != null) {
408 7309 leinfelder
        	if (clauseAdded) {
409 7451 leinfelder
                queryWhereClause.append(" and ");
410 7309 leinfelder
            }
411 7451 leinfelder
        	queryWhereClause.append("event in (");
412
    		queryWhereClause.append("?");
413 7287 leinfelder
    		String eventString = event.xmlValue();
414 7285 leinfelder
    		if (event.equals(Event.CREATE)) {
415
    			eventString = "insert";
416
    		}
417
    		paramValues.add(eventString);
418 7451 leinfelder
        	queryWhereClause.append(") ");
419 7285 leinfelder
            clauseAdded = true;
420
        }
421 7450 leinfelder
        else {
422 7437 leinfelder
	        if (clauseAdded) {
423 7451 leinfelder
	            queryWhereClause.append(" and ");
424 7437 leinfelder
	        }
425 7451 leinfelder
	    	queryWhereClause.append("event in (");
426 7437 leinfelder
	    	for (int i = 0; i < Event.values().length; i++) {
427
	    		if (i > 0) {
428 7451 leinfelder
	        		queryWhereClause.append(", ");
429 7437 leinfelder
	    		}
430 7451 leinfelder
	    		queryWhereClause.append("?");
431 7450 leinfelder
	    		Event e = Event.values()[i];
432
	    		String eventString = e.xmlValue();
433
	    		if (e.equals(Event.CREATE)) {
434
	    			eventString = "insert";
435
	    		}
436
	    		paramValues.add(eventString);
437 7437 leinfelder
	    	}
438 7451 leinfelder
	    	queryWhereClause.append(") ");
439 7437 leinfelder
	        clauseAdded = true;
440
        }
441 7285 leinfelder
        if (startDate != null) {
442
            if (clauseAdded) {
443 7451 leinfelder
                queryWhereClause.append(" and ");
444 7285 leinfelder
            }
445 7451 leinfelder
            queryWhereClause.append("date_logged >= ?");
446 7285 leinfelder
            clauseAdded = true;
447
        }
448
        if (endDate != null) {
449
            if (clauseAdded) {
450 7451 leinfelder
                queryWhereClause.append(" and ");
451 7285 leinfelder
            }
452 7451 leinfelder
            queryWhereClause.append("date_logged < ?");
453 7285 leinfelder
            clauseAdded = true;
454
        }
455 7437 leinfelder
456
        // order by
457 7451 leinfelder
        String orderByClause = " order by entryid ";
458 7437 leinfelder
459 7451 leinfelder
        // select the count
460
        String countQuery = countClause + queryWhereClause.toString();
461
462
		// select the fields
463
        String pagedQuery = DatabaseService.getInstance().getDBAdapter().getPagedQuery(fieldsClause + queryWhereClause.toString() + orderByClause, start, count);
464 7437 leinfelder
465 7285 leinfelder
        DBConnection dbConn = null;
466
        int serialNumber = -1;
467
        try {
468
            // Get a database connection from the pool
469
            dbConn = DBConnectionPool.getDBConnection("EventLog.getD1Report");
470
            serialNumber = dbConn.getCheckOutSerialNumber();
471
472
            // Execute the query statement
473 7451 leinfelder
            PreparedStatement fieldsStmt = dbConn.prepareStatement(pagedQuery);
474
            PreparedStatement countStmt = dbConn.prepareStatement(countQuery);
475
476 7285 leinfelder
            //set the param values
477
            int parameterIndex = 1;
478
            for (String val: paramValues) {
479 7451 leinfelder
            	countStmt.setString(parameterIndex, val);
480
            	fieldsStmt.setString(parameterIndex, val);
481
            	parameterIndex++;
482 7285 leinfelder
            }
483
            if (startDate != null) {
484 7451 leinfelder
            	countStmt.setTimestamp(parameterIndex, startDate);
485
                fieldsStmt.setTimestamp(parameterIndex, startDate);
486
            	parameterIndex++;
487 7285 leinfelder
            }
488
            if (endDate != null) {
489 7451 leinfelder
            	countStmt.setTimestamp(parameterIndex, endDate);
490
            	fieldsStmt.setTimestamp(parameterIndex, endDate);
491
            	parameterIndex++;
492 7285 leinfelder
            }
493 7451 leinfelder
494
            // for the return Log list
495 7285 leinfelder
            List<LogEntry> logs = new Vector<LogEntry>();
496
497 7451 leinfelder
            // get the fields form the query
498
            if (count != 0) {
499
	            fieldsStmt.execute();
500
	            ResultSet rs = fieldsStmt.getResultSet();
501
	            //process the result and return it
502
	            while (rs.next()) {
503
	            	LogEntry logEntry = new LogEntry();
504
	            	logEntry.setEntryId(rs.getString(1));
505
506
	            	Identifier identifier = new Identifier();
507
	            	identifier.setValue(rs.getString(2));
508
					logEntry.setIdentifier(identifier);
509
510
	            	logEntry.setIpAddress(anonymous ? "N/A" : rs.getString(3));
511
	            	String userAgent = "N/A";
512
	            	if (rs.getString(4) != null) {
513
	            		userAgent = rs.getString(4);
514
	            	}
515
	            	logEntry.setUserAgent(userAgent);
516
517
	            	Subject subject = new Subject();
518
	            	subject.setValue(anonymous ? "N/A" : rs.getString(5));
519
					logEntry.setSubject(subject);
520
521
					String logEventString = rs.getString(6);
522
					Event logEvent = Event.convert(logEventString );
523
					if (logEvent == null) {
524
						logMetacat.info("Skipping uknown DataONE Event type: " + logEventString);
525
						continue;
526
					}
527
					logEntry.setEvent(logEvent);
528
					logEntry.setDateLogged(rs.getTimestamp(7));
529
530
					logEntry.setNodeIdentifier(memberNode);
531
					logs.add(logEntry);
532
	            }
533
	            fieldsStmt.close();
534 7285 leinfelder
            }
535
536 7451 leinfelder
            // set what we have
537
            log.setLogEntryList(logs);
538 7285 leinfelder
		    log.setStart(start);
539
		    log.setCount(logs.size());
540 7451 leinfelder
541
			// get total for out query
542
		    int total = 0;
543
            countStmt.execute();
544
            ResultSet countRs = countStmt.getResultSet();
545
            if (countRs.next()) {
546
            	total = countRs.getInt(1);
547
            }
548
            countStmt.close();
549 7285 leinfelder
		    log.setTotal(total);
550
551
        } catch (SQLException e) {
552 7287 leinfelder
        	logMetacat.error("Error while getting log events: " + e.getMessage(), e);
553 7285 leinfelder
        } finally {
554
            // Return database connection to the pool
555
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
556
        }
557
        return log;
558
    }
559
560 2111 jones
    /**
561
     * Format each returned log record as an XML structure.
562
     *
563
     * @param entryId the identifier of the log entry
564
     * @param ipAddress the internet protocol address for the event
565 6542 leinfelder
     * @param the agent making the request
566 2111 jones
	 * @param principal the principal for the event (a username, etc)
567
	 * @param docid the identifier of the document to which the event applies
568
	 * @param event the string code for the event
569
     * @param dateLogged the date on which the event occurred
570
     * @return String containing the formatted XML
571
     */
572 6542 leinfelder
    private String generateXmlRecord(String entryId, String ipAddress, String userAgent,
573 2113 jones
            String principal, String docid, String event, Timestamp dateLogged)
574 2111 jones
    {
575
        StringBuffer rec = new StringBuffer();
576
        rec.append("<logEntry>");
577 2113 jones
        rec.append(generateXmlElement("entryid", entryId));
578
        rec.append(generateXmlElement("ipAddress", ipAddress));
579 6542 leinfelder
        rec.append(generateXmlElement("userAgent", userAgent));
580 2113 jones
        rec.append(generateXmlElement("principal", principal));
581
        rec.append(generateXmlElement("docid", docid));
582
        rec.append(generateXmlElement("event", event));
583 6944 leinfelder
        rec.append(generateXmlElement("dateLogged", DateTimeMarshaller.serializeDateToUTC(dateLogged)));
584 2111 jones
        rec.append("</logEntry>\n");
585
586
        return rec.toString();
587
    }
588
589
    /**
590
     * Return an XML formatted element for a given name/value pair.
591
     *
592
     * @param name the name of the xml element
593
     * @param value the content of the xml element
594
     * @return the formatted XML element as a String
595
     */
596 2113 jones
    private String generateXmlElement(String name, String value)
597 2111 jones
    {
598
        return "<" + name + ">" + value + "</" + name + ">";
599
    }
600 2096 jones
}