001: /*
002: * <copyright>
003: *
004: * Copyright 2002-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.yp;
028:
029: import java.io.BufferedReader;
030: import java.io.BufferedWriter;
031: import java.io.File;
032: import java.io.FileNotFoundException;
033: import java.io.FileReader;
034: import java.io.FileWriter;
035: import java.io.IOException;
036: import java.util.ArrayList;
037: import java.util.List;
038: import java.util.Properties;
039:
040: import javax.xml.parsers.DocumentBuilder;
041: import javax.xml.parsers.DocumentBuilderFactory;
042:
043: import org.cougaar.core.agent.service.alarm.Alarm;
044: import org.cougaar.core.agent.service.MessageSwitchService;
045: import org.cougaar.core.component.ComponentSupport;
046: import org.cougaar.core.component.ServiceBroker;
047: import org.cougaar.core.mts.Message;
048: import org.cougaar.core.mts.MessageAddress;
049: import org.cougaar.core.mts.MessageHandler;
050: import org.cougaar.core.persist.PersistenceClient;
051: import org.cougaar.core.persist.PersistenceIdentity;
052: import org.cougaar.core.persist.PersistenceService;
053: import org.cougaar.core.persist.RehydrationData;
054: import org.cougaar.core.service.AlarmService;
055: import org.cougaar.core.service.ThreadService;
056: import org.cougaar.util.log.Logger;
057: import org.cougaar.util.log.Logging;
058: import org.cougaar.util.TimeSpan;
059:
060: import org.juddi.error.JUDDIException;
061: import org.juddi.service.ServiceFactory;
062: import org.juddi.service.UDDIService;
063: import org.juddi.transport.axis.RequestFactory;
064: import org.juddi.util.Config;
065:
066: import org.uddi4j.UDDIElement;
067: import org.uddi4j.response.DispositionReport;
068:
069: import org.w3c.dom.Document;
070: import org.w3c.dom.Element;
071: import org.w3c.dom.Node;
072:
073: /**
074: * This is the basic in-memory YP Server component.
075: * We use soapuddi to deal with the queries and
076: * hsqldb in in-memory mode as a database.
077: **/
078:
079: public class YPServer extends ComponentSupport {
080: private static final Logger logger = Logging
081: .getLogger(YPServer.class);
082:
083: // create an XML document builder factory
084: private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
085: .newInstance();
086:
087: private static long UNUSED_DBCONNECTION_TIMEOUT = 10; // in minutes
088: private static final String UNUSED_DBCONNECTION_TIMEOUT_PROPERTY = "org.cougaar.yp.UnusedDBConnectionInterval";
089: private static final long MILLI_PER_MINUTE = (60 * 1000);
090:
091: static {
092: UNUSED_DBCONNECTION_TIMEOUT = MILLI_PER_MINUTE
093: * Integer.getInteger(
094: UNUSED_DBCONNECTION_TIMEOUT_PROPERTY,
095: (int) UNUSED_DBCONNECTION_TIMEOUT).longValue();
096: }
097:
098: private DocumentBuilder builder;
099: private MessageSwitchService mss = null;
100: private MessageAddress originMA;
101: private String dbName;
102:
103: private long lastMessageTime = TimeSpan.MIN_VALUE;
104: private Alarm timerAlarm = null;
105:
106: private DocumentBuilder getBuilder() {
107: if (builder == null) {
108: try {
109: builder = documentBuilderFactory.newDocumentBuilder();
110: } catch (Exception e) {
111: logger.error("Could not create builder factory", e);
112: }
113: }
114: return builder;
115: }
116:
117: /** alarm service for closing unused connections
118: **/
119: private AlarmService alarmService;
120:
121: public void setAlarmService(AlarmService as) {
122: this .alarmService = as;
123: }
124:
125: protected final AlarmService getAlarmService() {
126: return alarmService;
127: }
128:
129: /** threading service for launching our service thread, set by introspection **/
130: private ThreadService threadService;
131:
132: public void setThreadService(ThreadService ts) {
133: this .threadService = ts;
134: }
135:
136: // must use explicit getService
137: private PersistenceService persistenceService;
138: private PersistenceIdentity persistenceIdentity = new PersistenceIdentity(
139: YPServer.class.getName());
140:
141: protected final String installPath = System.getProperty(
142: "org.cougaar.install.path", "/tmp");
143: protected final String workspacePath = System.getProperty(
144: "org.cougaar.workspace", installPath + "/workspace");
145: protected File dbDirectory;
146:
147: public YPServer() {
148: String hp = System.getProperty("juddi.homeDir", "");
149: if (hp.equals("")) {
150: hp = workspacePath + "/juddi";
151: System.setProperty("juddi.homeDir", hp);
152: }
153: }
154:
155: public void load() {
156: super .load();
157: ServiceBroker sb = getServiceBroker();
158:
159: persistenceService = (PersistenceService) sb.getService(
160: new PersistenceClient() {
161: public PersistenceIdentity getPersistenceIdentity() {
162: return persistenceIdentity;
163: }
164:
165: public List getPersistenceData() {
166: return encapsulateDatabase();
167: }
168: }, PersistenceService.class, null);
169:
170: RehydrationData rd = persistenceService.getRehydrationData();
171: if (rd != null) {
172: deencapsulateDatabase(rd);
173: }
174:
175: // Must get the MessageSwitchService and MessageAddress before
176: // registering the MessageHandler - cause messages may start pouring in
177: mss = (MessageSwitchService) sb.getService(this ,
178: MessageSwitchService.class, null);
179: if (mss == null) {
180: throw new RuntimeException(
181: "YPServer couldnt get MessageSwitchService!");
182: }
183:
184: originMA = mss.getMessageAddress();
185: if (originMA == null) {
186: throw new RuntimeException(
187: "YPServer got null MessageAddress for local Agent from MessageSwitchService!");
188: }
189:
190: initUDDI();
191: initDB(); // uses rehydrated database information, if available
192:
193: startServiceThread();
194:
195: // need to hook into the Agent MessageHandler protocol
196: MessageHandler mh = new MessageHandler() {
197: public boolean handleMessage(Message message) {
198: if (message instanceof YPQueryMessage) {
199: if (logger.isDebugEnabled()) {
200: logger.debug("handleMessage: source "
201: + message.getOriginator()
202: + " target "
203: + message.getTarget()
204: + " key "
205: + ((YPQueryMessage) message).getKey()
206: + " element "
207: + ((YPQueryMessage) message)
208: .getElement());
209: }
210:
211: getServiceThread().addMessage(
212: (YPQueryMessage) message);
213: return true;
214: }
215: return false;
216: }
217: };
218:
219: mss.addMessageHandler(mh);
220: }
221:
222: public void suspend() {
223: if (logger.isInfoEnabled()) {
224: logger.info(originMA.toString() + " suspending");
225: }
226:
227: // suspend all children
228: if (logger.isInfoEnabled()) {
229: logger.info(originMA.toString()
230: + "Recursively suspending all child components");
231: }
232: super .suspend();
233:
234: if (logger.isInfoEnabled()) {
235: logger
236: .info(originMA.toString()
237: + " dropping database connection for persistence snapshot");
238: }
239:
240: Config.dbTag.set(dbName);
241: org.juddi.datastore.jdbc.HSQLDataStoreFactory.closeConnection();
242:
243: if (timerAlarm != null) {
244: if (logger.isInfoEnabled()) {
245: logger.info(originMA.toString()
246: + "suspend - cancelling timerAlarm.");
247: }
248: timerAlarm.cancel();
249: }
250:
251: getServiceBroker().releaseService(this ,
252: MessageSwitchService.class, mss);
253: /*
254: getServiceBroker().releaseService(this, PersistenceService.class,
255: persistenceService);
256: */
257: getServiceBroker().releaseService(this , ThreadService.class,
258: threadService);
259: }
260:
261: public void resume() {
262: super .resume();
263:
264: // Restart database????
265: }
266:
267: //
268: // persistence
269: //
270: private List encapsulateDatabase() {
271:
272: List l = new ArrayList(1);
273: DatabaseEnvelope de = getDatabaseEnvelope();
274: if (DatabaseEnvelope.logger.isInfoEnabled()) {
275: DatabaseEnvelope.logger
276: .info("Encapsulating database " + de);
277: }
278: l.add(de);
279: return l;
280: }
281:
282: private void deencapsulateDatabase(RehydrationData rd) {
283: List l = rd.getObjects();
284: try {
285: DatabaseEnvelope de = (DatabaseEnvelope) l.get(0);
286: DatabaseEnvelope.logger.info("Dencapsulating database "
287: + de);
288: setDatabaseEnvelope(de);
289: } catch (Exception e) { // arrayOOB, classcast, etc
290: logger.error("Persistence snapshot objects corrupt", e);
291: }
292: }
293:
294: private DatabaseEnvelope databaseEnvelope = null;
295: private final DatabaseEnvelope.Locker databaseLocker = new DatabaseEnvelope.Locker() {
296: public void stop() {
297: }
298:
299: public void start() {
300: }
301: };
302:
303: protected DatabaseEnvelope getDatabaseEnvelope() {
304: synchronized (databaseLocker) {
305: return databaseEnvelope;
306: }
307: }
308:
309: // mutations of the database should create a new DBE instance and set
310: protected void setDatabaseEnvelope(DatabaseEnvelope de) {
311: synchronized (databaseLocker) {
312: databaseEnvelope = de;
313: }
314: }
315:
316: /** Called each time the database is modified **/
317: private void snapshotDatabase() {
318: synchronized (databaseLocker) {
319: databaseEnvelope = new DatabaseEnvelope(dbDirectory,
320: databaseLocker);
321: }
322: }
323:
324: //
325: // Service thread for incoming (response) messages
326: //
327:
328: private ServiceThread serviceThread = null;
329:
330: private void startServiceThread() {
331: serviceThread = new ServiceThread(new ServiceThread.Callback() {
332: public void dispatch(Message m) {
333: if (logger.isDebugEnabled()) {
334: ThreadGroup threadGroup = Thread.currentThread()
335: .getThreadGroup();
336: Thread threads[] = new Thread[threadGroup
337: .activeCount()];
338: threadGroup.enumerate(threads);
339: logger.debug(originMA
340: + " thread count before dispatch = "
341: + threadGroup.activeCount());
342: for (int index = 0; index < threads.length; index++) {
343: Thread thread = threads[index];
344: if (thread == null) {
345: logger.debug("\t thread = " + null);
346: } else if (!thread.getName().startsWith(
347: "CougaarPooledThread")) {
348: logger.debug("\t name = "
349: + thread.getName()
350: + " threadGroup = "
351: + thread.getThreadGroup()
352: + " class = " + thread.getClass()
353: + " " + thread);
354: }
355: }
356: }
357:
358: lastMessageTime = System.currentTimeMillis();
359: startTimer();
360:
361: Config.dbTag.set(dbName);
362: dispatchQuery((YPQueryMessage) m);
363:
364: }
365: }, logger, "YPServer(" + originMA + ")");
366: serviceThread.start(threadService);
367: }
368:
369: protected ServiceThread getServiceThread() {
370: return serviceThread;
371: }
372:
373: //
374: // Timer - close unused db connection
375: //
376:
377: private void startTimer() {
378: if ((timerAlarm == null) || (timerAlarm.hasExpired())) {
379: timerAlarm = new TimerAlarm(System.currentTimeMillis()
380: + UNUSED_DBCONNECTION_TIMEOUT);
381:
382: if (logger.isDebugEnabled()) {
383: logger.debug("startTimer() - adding new TimerAlarm "
384: + timerAlarm);
385: }
386: getAlarmService().addRealTimeAlarm(timerAlarm);
387: } else if (logger.isDebugEnabled()) {
388: logger.debug("startTimer() - ignoring request. "
389: + "Active TimerAlarm already exists " + timerAlarm
390: + "currentTimeMillis() = "
391: + System.currentTimeMillis()
392: + " disconnect timeout = "
393: + UNUSED_DBCONNECTION_TIMEOUT);
394: }
395: }
396:
397: public class TimerAlarm implements Alarm {
398: private long expiresAt;
399: private boolean expired = false;
400:
401: public TimerAlarm(long expirationTime) {
402: expiresAt = expirationTime;
403: }
404:
405: public long getExpirationTime() {
406: return expiresAt;
407: }
408:
409: public synchronized void expire() {
410: if (!expired) {
411: expired = true;
412:
413: if (lastMessageTime < (System.currentTimeMillis() - UNUSED_DBCONNECTION_TIMEOUT)) {
414: if (logger.isDebugEnabled()) {
415: logger
416: .debug("expire() - closing connection, lastMessageTime = "
417: + lastMessageTime
418: + " expired alarm = " + this );
419: }
420: Config.dbTag.set(dbName);
421: org.juddi.datastore.jdbc.HSQLDataStoreFactory
422: .closeConnection();
423: } else {
424: if (logger.isDebugEnabled()) {
425: logger
426: .debug("expire() - leaving connection open, lastMessageTime = "
427: + lastMessageTime
428: + " expired alarm = " + this );
429: }
430: startTimer();
431: }
432: }
433: }
434:
435: public synchronized boolean hasExpired() {
436: return expired;
437: }
438:
439: public synchronized boolean cancel() {
440: boolean was = expired;
441: expired = true;
442: return was;
443: }
444:
445: public synchronized String toString() {
446: return "<TimerAlarm " + expiresAt
447: + (expired ? "(Expired) " : " ")
448: + "for YPServer at " + originMA + ">";
449: }
450: }
451:
452: private int rc = 0;
453:
454: private synchronized void dispatchQuery(YPQueryMessage r) {
455: if (logger.isDebugEnabled()) {
456: logger.debug("dispatchQuery: query: " + r.getKey() + " "
457: + r.getElement());
458: }
459:
460: Object key = r.getKey();
461: Element qel = r.getElement();
462: Element rel = null;
463: boolean isInquiry = r.isInquiry();
464: synchronized (databaseLocker) {
465: rel = executeQuery(qel);
466: if (!isInquiry) {
467: snapshotDatabase();
468: }
469: }
470: YPResponseMessage m = new YPResponseMessage(originMA, r
471: .getOriginator(), rel, key);
472:
473: if (logger.isDebugEnabled()) {
474: logger.debug("dispatchQuery: response - source " + originMA
475: + " target " + r.getOriginator() + " key " + key
476: + " rel " + rel);
477: }
478: sendMessage(m);
479: rc++;
480: }
481:
482: protected void sendMessage(Message m) {
483: mss.sendMessage(m);
484: }
485:
486: //public static final String DB_URL = "jdbc:hsqldb:.";
487: public static final String DB_FILE = "foodb";
488: public static final String DB_URL = "jdbc:hsqldb:" + DB_FILE;
489: public static final String DB_DRIVER = "org.hsqldb.jdbcDriver";
490: public static final String DB_USER = "sa";
491: public static final String DB_PASS = "";
492:
493: Element executeQuery(Element qel) {
494: try {
495: if (logger.isDebugEnabled()) {
496: logger.debug("executeQuery: query -");
497: describeElement(qel);
498: }
499:
500: Document document = getBuilder().newDocument();
501: Element holder = document.createElement("holder");
502: document.appendChild(holder); // holder element is thrown away
503: Element response = document.getDocumentElement();
504:
505: UDDIElement request = (UDDIElement) RequestFactory
506: .getRequest(qel);
507: UDDIService uService = ServiceFactory.getService(request
508: .getClass().getName());
509:
510: try {
511: uService.invoke(request).saveToXML(response);
512:
513: if (logger.isDebugEnabled()) {
514: logger.debug("executeQuery: returned -");
515: describeElement(response);
516: }
517: return (Element) response.getChildNodes().item(0);
518:
519: } catch (JUDDIException je) {
520: Element fault = getFaultDoc(je);
521: if (logger.isWarnEnabled()) {
522: logger.warn("executeQuery: fault", je);
523: }
524: return fault;
525: }
526:
527: } catch (Exception e) {
528: logger.error("Uncaught Exception ", e);
529: return null;
530: }
531: }
532:
533: // from JUDDI/../JUDDIProxy
534: private Element getFaultDoc(JUDDIException e) {
535: DocumentBuilderFactory factory = DocumentBuilderFactory
536: .newInstance();
537: try {
538: Element faultElement = null;
539: Element rootElement = null;
540:
541: // 2. build up a response element for UDDI4j to 'saveToXML()' into
542: DocumentBuilder builder = factory.newDocumentBuilder();
543: Document faultDoc = builder.newDocument();
544: rootElement = faultDoc.createElement("Fault");
545: faultDoc.appendChild(rootElement);
546:
547: faultElement = faultDoc.createElement("faultcode");
548: faultElement.appendChild(faultDoc.createTextNode(e
549: .getFaultCode()));
550: rootElement.appendChild(faultElement);
551:
552: faultElement = faultDoc.createElement("faultstring");
553: if (e.getFaultString() != null) {
554: faultElement.appendChild(faultDoc.createTextNode(e
555: .getFaultString()));
556: } else {
557: faultElement.appendChild(faultDoc.createTextNode(e
558: .getMessage()));
559: }
560: rootElement.appendChild(faultElement);
561:
562: faultElement = faultDoc.createElement("faultactor");
563: faultElement.appendChild(faultDoc.createTextNode(e
564: .getFaultActor()));
565: rootElement.appendChild(faultElement);
566:
567: DispositionReport dispRpt = e.getDispositionReport();
568: if (dispRpt != null) {
569: faultElement = faultDoc.createElement("detail");
570: dispRpt.saveToXML(faultElement);
571: rootElement.appendChild(faultElement);
572: }
573:
574: return rootElement;
575: } catch (Exception pcex) {
576: System.out.println(pcex.getMessage());
577: return null;
578: }
579: }
580:
581: static void describeElement(Node el) {
582: describeElement(el, "");
583: }
584:
585: static void describeElement(Node el, String prefix) {
586: System.out.println(prefix + el);
587: String pn = prefix + " ";
588: if (el.hasChildNodes()) {
589: for (Node c = el.getFirstChild(); c != null; c = c
590: .getNextSibling()) {
591: describeElement(c, pn);
592: }
593: }
594: }
595:
596: private void copyFiles(String ypDir, String juddiDir) {
597: File ypSourceDir = new File(installPath + File.separator + "yp"
598: + File.separator + "data" + File.separator + "juddi"
599: + File.separator + ypDir);
600: File newDir = new File(juddiDir);
601:
602: try {
603:
604: if (!ypSourceDir.canRead()) {
605: logger.fatal("ypSourceDir: unable to read "
606: + ypSourceDir.getPath() + " directory");
607: return;
608: }
609:
610: File[] ypSourceFiles = ypSourceDir.listFiles();
611: for (int index = 0; index < ypSourceFiles.length; index++) {
612: File ypSourceFile = ypSourceFiles[index];
613: if (ypSourceFile.isFile()) {
614: BufferedReader in = new BufferedReader(
615: new FileReader(ypSourceFile));
616:
617: BufferedWriter out = new BufferedWriter(
618: new FileWriter(new File(newDir,
619: ypSourceFile.getName())));
620: String inLine;
621: while ((inLine = in.readLine()) != null) {
622: out.write(inLine);
623: out.newLine();
624: }
625:
626: in.close();
627: out.close();
628: }
629: }
630: } catch (FileNotFoundException fnfe) {
631: logger.fatal("copyFiles: error copying "
632: + ypSourceDir.getPath() + " files.", fnfe);
633: } catch (IOException ioe) {
634: logger.fatal("copyFiles: error copying "
635: + ypSourceDir.getPath() + " files.", ioe);
636: }
637: }
638:
639: void initDB() {
640: String juddiHomeDirProperty = System.getProperty(
641: "juddi.homeDir", "");
642: long timestamp = System.currentTimeMillis();
643: dbName = originMA.toString() + "@" + timestamp;
644:
645: File juddiHomeDir = new File(juddiHomeDirProperty, dbName);
646: if (!juddiHomeDir.isDirectory()) {
647: if (!juddiHomeDir.mkdirs()) {
648: logger.fatal("Unable to access jUDDI home directory "
649: + juddiHomeDir.getAbsolutePath());
650: return;
651: }
652: }
653:
654: File confDir = new File(juddiHomeDir, "conf");
655: if (!confDir.isDirectory()) {
656: if (!confDir.mkdirs()) {
657: logger
658: .fatal("Unable to access jUDDI configuration directory "
659: + confDir.getAbsolutePath());
660: return;
661: }
662: }
663:
664: copyFiles("conf", confDir.toString());
665:
666: Config.dbTag.set(dbName);
667: if (logger.isDebugEnabled()) {
668: // verify that we agree with juddi on home and config directories
669: logger.debug(originMA.toString() + ": juddi home = "
670: + Config.getHomeDir()
671: + " YPServer thinks juddi home = " + juddiHomeDir);
672:
673: logger.debug(originMA.toString() + ": juddi config = "
674: + Config.getConfigDir()
675: + " YPServer thinks juddi config = " + confDir);
676: }
677:
678: dbDirectory = new File(Config.getHomeDir(), "hsql");
679: dbDirectory.mkdirs();
680:
681: synchronized (databaseLocker) {
682: if (databaseEnvelope != null) { // rehydrate!
683: try {
684: databaseEnvelope.dumpPayload(dbDirectory);
685: snapshotDatabase(); // re-snapshot to avoid keeping a big array around
686: // Note that this call re-syncs on databaseLocker
687: // but we don't want a gap.
688: return; // done - all is well
689: } catch (IOException ioe) {
690: logger.error("Unrecoverable database snapshot "
691: + dbDirectory, ioe);
692: }
693: }
694:
695: // no successful recovery, so we'll have to start over
696: org.juddi.datastore.jdbc.HSQLDataStoreFactory.getURL();
697: copyFiles("hsql", dbDirectory.getPath());
698: snapshotDatabase(); // take a snapshot immediately
699: }
700: //hack();
701: }
702:
703: void initUDDI() {
704: Properties props = new Properties();
705: props.setProperty("operator", "Cougaar");
706: props.setProperty("user", DB_USER);
707: props.setProperty("passwd", DB_PASS);
708: props.setProperty("authorisedName", "auser");
709:
710: props.setProperty("Class", DB_DRIVER);
711: props.setProperty("URL", DB_URL);
712:
713: //com.induslogic.uddi.server.util.GlobalProperties.loadProperties(props);
714: }
715:
716: /*
717: void hack() {
718: try {
719: File target = new File("/tmp/hsql/"+originMA.toString());
720: target.mkdirs();
721:
722: DatabaseEnvelope.logger.info("Hack, writing binfile");
723: String binf = "/tmp/"+originMA+".bin";
724: ObjectOutputStream os = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(binf)));
725: os.writeObject(getDatabaseEnvelope());
726: os.close();
727: DatabaseEnvelope.logger.info("Hack, reading binfile");
728: ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(new FileInputStream(binf)));
729: DatabaseEnvelope de = (DatabaseEnvelope) is.readObject();
730: DatabaseEnvelope.logger.info("Hack, read "+de);
731: de.dumpPayload(target);
732: DatabaseEnvelope.logger.info("Dumped payload to "+target);
733: } catch (Exception e) {
734: e.printStackTrace();
735: }
736: }
737: */
738: }
|