From c4578dc062e7610f400f33f1ad4bbdfc5aab532c Mon Sep 17 00:00:00 2001 From: Lennart Koopmann Date: Thu, 14 Mar 2013 22:08:21 +0100 Subject: [PATCH] initial --- README | 1 + pom.xml | 48 + .../productivity/java/syslog4j/Syslog.java | 318 +++ .../java/syslog4j/Syslog4jVersion.java | 16 + .../java/syslog4j/SyslogBackLogHandlerIF.java | 51 + .../java/syslog4j/SyslogCharSetIF.java | 19 + .../java/syslog4j/SyslogConfigIF.java | 69 + .../java/syslog4j/SyslogConstants.java | 164 ++ .../productivity/java/syslog4j/SyslogIF.java | 52 + .../java/syslog4j/SyslogMain.java | 198 ++ .../java/syslog4j/SyslogMessageIF.java | 17 + .../SyslogMessageModifierConfigIF.java | 20 + .../syslog4j/SyslogMessageModifierIF.java | 17 + .../syslog4j/SyslogMessageProcessorIF.java | 22 + .../java/syslog4j/SyslogPoolConfigIF.java | 52 + .../java/syslog4j/SyslogRuntimeException.java | 24 + .../java/syslog4j/impl/AbstractSyslog.java | 394 ++++ .../syslog4j/impl/AbstractSyslogConfig.java | 378 ++++ .../syslog4j/impl/AbstractSyslogConfigIF.java | 56 + .../syslog4j/impl/AbstractSyslogWriter.java | 109 + .../backlog/AbstractSyslogBackLogHandler.java | 36 + .../backlog/NullSyslogBackLogHandler.java | 35 + .../impl/backlog/Syslog4jBackLogHandler.java | 67 + .../log4j/Log4jSyslogBackLogHandler.java | 148 ++ .../PrintStreamSyslogBackLogHandler.java | 69 + .../SystemErrSyslogBackLogHandler.java | 27 + .../SystemOutSyslogBackLogHandler.java | 27 + .../syslog4j/impl/log4j/Syslog4jAppender.java | 79 + .../impl/log4j/Syslog4jAppenderSkeleton.java | 331 +++ .../impl/message/AbstractSyslogMessage.java | 101 + .../AbstractSyslogMessageModifier.java | 63 + .../AbstractSyslogMessageModifierConfig.java | 58 + .../ChecksumSyslogMessageModifier.java | 101 + .../ChecksumSyslogMessageModifierConfig.java | 57 + ...HTMLEntityEscapeSyslogMessageModifier.java | 80 + .../hash/HashSyslogMessageModifier.java | 132 ++ .../hash/HashSyslogMessageModifierConfig.java | 66 + .../mac/MacSyslogMessageModifier.java | 120 ++ .../mac/MacSyslogMessageModifierConfig.java | 108 + .../SequentialSyslogMessageModifier.java | 101 + ...SequentialSyslogMessageModifierConfig.java | 74 + .../text/PrefixSyslogMessageModifier.java | 59 + .../text/StringCaseSyslogMessageModifier.java | 58 + .../text/SuffixSyslogMessageModifier.java | 59 + .../impl/message/pci/PCISyslogMessage.java | 256 +++ .../impl/message/pci/PCISyslogMessageIF.java | 30 + .../AbstractSyslogMessageProcessor.java | 118 ++ .../processor/SyslogMessageProcessor.java | 35 + .../StructuredSyslogMessageProcessor.java | 106 + .../structured/StructuredSyslogMessage.java | 391 ++++ .../structured/StructuredSyslogMessageIF.java | 18 + .../impl/multiple/MultipleSyslog.java | 174 ++ .../impl/multiple/MultipleSyslogConfig.java | 241 +++ .../syslog4j/impl/net/AbstractNetSyslog.java | 61 + .../impl/net/AbstractNetSyslogConfig.java | 85 + .../impl/net/AbstractNetSyslogConfigIF.java | 19 + .../syslog4j/impl/net/tcp/TCPNetSyslog.java | 91 + .../impl/net/tcp/TCPNetSyslogConfig.java | 156 ++ .../impl/net/tcp/TCPNetSyslogConfigIF.java | 40 + .../impl/net/tcp/TCPNetSyslogWriter.java | 226 ++ .../impl/net/tcp/pool/PooledTCPNetSyslog.java | 76 + .../tcp/pool/PooledTCPNetSyslogConfig.java | 172 ++ .../impl/net/tcp/ssl/SSLTCPNetSyslog.java | 49 + .../net/tcp/ssl/SSLTCPNetSyslogConfig.java | 88 + .../net/tcp/ssl/SSLTCPNetSyslogConfigIF.java | 28 + .../net/tcp/ssl/SSLTCPNetSyslogWriter.java | 28 + .../ssl/pool/PooledSSLTCPNetSyslogConfig.java | 91 + .../syslog4j/impl/net/udp/UDPNetSyslog.java | 104 + .../impl/net/udp/UDPNetSyslogConfig.java | 46 + .../impl/pool/AbstractSyslogPoolFactory.java | 84 + .../generic/GenericSyslogPoolFactory.java | 52 + .../java/syslog4j/impl/unix/UnixSyslog.java | 125 ++ .../syslog4j/impl/unix/UnixSyslogConfig.java | 71 + .../impl/unix/socket/UnixSocketSyslog.java | 143 ++ .../unix/socket/UnixSocketSyslogConfig.java | 141 ++ .../java/syslog4j/server/SyslogServer.java | 239 +++ .../syslog4j/server/SyslogServerConfigIF.java | 50 + .../server/SyslogServerEventHandlerIF.java | 8 + .../syslog4j/server/SyslogServerEventIF.java | 41 + .../java/syslog4j/server/SyslogServerIF.java | 27 + .../syslog4j/server/SyslogServerMain.java | 165 ++ .../SyslogServerSessionEventHandlerIF.java | 10 + ...SyslogServerSessionlessEventHandlerIF.java | 20 + .../server/impl/AbstractSyslogServer.java | 339 +++ .../impl/AbstractSyslogServerConfig.java | 106 + .../server/impl/event/SyslogServerEvent.java | 213 ++ .../FileSyslogServerEventHandler.java | 29 + .../PrintStreamSyslogServerEventHandler.java | 59 + .../SystemErrSyslogServerEventHandler.java | 15 + .../SystemOutSyslogServerEventHandler.java | 15 + .../StructuredSyslogServerEvent.java | 151 ++ .../net/AbstractNetSyslogServerConfig.java | 37 + .../impl/net/tcp/TCPNetSyslogServer.java | 252 +++ .../net/tcp/TCPNetSyslogServerConfig.java | 86 + .../net/tcp/TCPNetSyslogServerConfigIF.java | 30 + .../net/tcp/ssl/SSLTCPNetSyslogServer.java | 58 + .../tcp/ssl/SSLTCPNetSyslogServerConfig.java | 59 + .../ssl/SSLTCPNetSyslogServerConfigIF.java | 27 + .../impl/net/udp/UDPNetSyslogServer.java | 102 + .../net/udp/UDPNetSyslogServerConfig.java | 38 + .../java/syslog4j/util/Base64.java | 1815 +++++++++++++++++ .../java/syslog4j/util/OSDetectUtility.java | 77 + .../java/syslog4j/util/SyslogUtility.java | 208 ++ .../productivity/java/syslog4j/Syslog.class | Bin 0 -> 6142 bytes .../java/syslog4j/Syslog4jVersion.class | Bin 0 -> 440 bytes .../syslog4j/SyslogBackLogHandlerIF.class | Bin 0 -> 513 bytes .../java/syslog4j/SyslogCharSetIF.class | Bin 0 -> 259 bytes .../java/syslog4j/SyslogConfigIF.class | Bin 0 -> 1755 bytes .../java/syslog4j/SyslogConstants.class | Bin 0 -> 5778 bytes .../productivity/java/syslog4j/SyslogIF.class | Bin 0 -> 1292 bytes .../java/syslog4j/SyslogMain$Options.class | Bin 0 -> 792 bytes .../java/syslog4j/SyslogMain.class | Bin 0 -> 5654 bytes .../java/syslog4j/SyslogMessageIF.class | Bin 0 -> 217 bytes .../SyslogMessageModifierConfigIF.class | Bin 0 -> 405 bytes .../syslog4j/SyslogMessageModifierIF.class | Bin 0 -> 354 bytes .../syslog4j/SyslogMessageProcessorIF.class | Bin 0 -> 327 bytes .../java/syslog4j/SyslogPoolConfigIF.class | Bin 0 -> 947 bytes .../syslog4j/SyslogRuntimeException.class | Bin 0 -> 625 bytes .../java/syslog4j/impl/AbstractSyslog.class | Bin 0 -> 11881 bytes .../syslog4j/impl/AbstractSyslogConfig.class | Bin 0 -> 9150 bytes .../impl/AbstractSyslogConfigIF.class | Bin 0 -> 919 bytes .../syslog4j/impl/AbstractSyslogWriter.class | Bin 0 -> 3422 bytes .../AbstractSyslogBackLogHandler.class | Bin 0 -> 1288 bytes .../backlog/NullSyslogBackLogHandler.class | Bin 0 -> 1170 bytes .../impl/backlog/Syslog4jBackLogHandler.class | Bin 0 -> 2798 bytes .../log4j/Log4jSyslogBackLogHandler.class | Bin 0 -> 4353 bytes .../PrintStreamSyslogBackLogHandler.class | Bin 0 -> 2553 bytes .../SystemErrSyslogBackLogHandler.class | Bin 0 -> 863 bytes .../SystemOutSyslogBackLogHandler.class | Bin 0 -> 863 bytes .../impl/log4j/Syslog4jAppender.class | Bin 0 -> 1142 bytes .../impl/log4j/Syslog4jAppenderSkeleton.class | Bin 0 -> 8002 bytes .../impl/message/AbstractSyslogMessage.class | Bin 0 -> 2925 bytes .../AbstractSyslogMessageModifier.class | Bin 0 -> 2066 bytes .../AbstractSyslogMessageModifierConfig.class | Bin 0 -> 1361 bytes .../ChecksumSyslogMessageModifier.class | Bin 0 -> 3980 bytes .../ChecksumSyslogMessageModifierConfig.class | Bin 0 -> 1505 bytes ...TMLEntityEscapeSyslogMessageModifier.class | Bin 0 -> 2201 bytes .../hash/HashSyslogMessageModifier.class | Bin 0 -> 4184 bytes .../HashSyslogMessageModifierConfig.class | Bin 0 -> 1580 bytes .../mac/MacSyslogMessageModifier.class | Bin 0 -> 4607 bytes .../mac/MacSyslogMessageModifierConfig.class | Bin 0 -> 3107 bytes .../SequentialSyslogMessageModifier.class | Bin 0 -> 3147 bytes ...equentialSyslogMessageModifierConfig.class | Bin 0 -> 2038 bytes .../text/PrefixSyslogMessageModifier.class | Bin 0 -> 1788 bytes .../StringCaseSyslogMessageModifier.class | Bin 0 -> 1596 bytes .../text/SuffixSyslogMessageModifier.class | Bin 0 -> 1788 bytes .../impl/message/pci/PCISyslogMessage.class | Bin 0 -> 7092 bytes .../impl/message/pci/PCISyslogMessageIF.class | Bin 0 -> 342 bytes .../AbstractSyslogMessageProcessor.class | Bin 0 -> 3084 bytes .../processor/SyslogMessageProcessor.class | Bin 0 -> 998 bytes .../StructuredSyslogMessageProcessor.class | Bin 0 -> 3245 bytes .../structured/StructuredSyslogMessage.class | Bin 0 -> 6662 bytes .../StructuredSyslogMessageIF.class | Bin 0 -> 240 bytes .../impl/multiple/MultipleSyslog.class | Bin 0 -> 5110 bytes .../impl/multiple/MultipleSyslogConfig.class | Bin 0 -> 6442 bytes .../syslog4j/impl/net/AbstractNetSyslog.class | Bin 0 -> 1867 bytes .../impl/net/AbstractNetSyslogConfig.class | Bin 0 -> 2286 bytes .../impl/net/AbstractNetSyslogConfigIF.class | Bin 0 -> 309 bytes .../syslog4j/impl/net/tcp/TCPNetSyslog.class | Bin 0 -> 2702 bytes .../impl/net/tcp/TCPNetSyslogConfig.class | Bin 0 -> 4452 bytes .../impl/net/tcp/TCPNetSyslogConfigIF.class | Bin 0 -> 732 bytes .../impl/net/tcp/TCPNetSyslogWriter.class | Bin 0 -> 5457 bytes .../net/tcp/pool/PooledTCPNetSyslog.class | Bin 0 -> 2111 bytes .../tcp/pool/PooledTCPNetSyslogConfig.class | Bin 0 -> 4906 bytes .../impl/net/tcp/ssl/SSLTCPNetSyslog.class | Bin 0 -> 1704 bytes .../net/tcp/ssl/SSLTCPNetSyslogConfig.class | Bin 0 -> 2609 bytes .../net/tcp/ssl/SSLTCPNetSyslogConfigIF.class | Bin 0 -> 510 bytes .../net/tcp/ssl/SSLTCPNetSyslogWriter.class | Bin 0 -> 665 bytes .../pool/PooledSSLTCPNetSyslogConfig.class | Bin 0 -> 2648 bytes .../syslog4j/impl/net/udp/UDPNetSyslog.class | Bin 0 -> 2801 bytes .../impl/net/udp/UDPNetSyslogConfig.class | Bin 0 -> 1274 bytes .../impl/pool/AbstractSyslogPoolFactory.class | Bin 0 -> 2850 bytes .../generic/GenericSyslogPoolFactory.class | Bin 0 -> 2592 bytes .../impl/unix/UnixSyslog$CLibrary.class | Bin 0 -> 408 bytes .../java/syslog4j/impl/unix/UnixSyslog.class | Bin 0 -> 3834 bytes .../syslog4j/impl/unix/UnixSyslogConfig.class | Bin 0 -> 2176 bytes .../socket/UnixSocketSyslog$CLibrary.class | Bin 0 -> 645 bytes .../socket/UnixSocketSyslog$SockAddr.class | Bin 0 -> 1081 bytes .../impl/unix/socket/UnixSocketSyslog.class | Bin 0 -> 3614 bytes .../unix/socket/UnixSocketSyslogConfig.class | Bin 0 -> 4047 bytes .../java/syslog4j/server/SyslogServer.class | Bin 0 -> 6313 bytes .../server/SyslogServerConfigIF.class | Bin 0 -> 1221 bytes .../server/SyslogServerEventHandlerIF.class | Bin 0 -> 298 bytes .../syslog4j/server/SyslogServerEventIF.class | Bin 0 -> 576 bytes .../java/syslog4j/server/SyslogServerIF.class | Bin 0 -> 616 bytes .../server/SyslogServerMain$Options.class | Bin 0 -> 778 bytes .../syslog4j/server/SyslogServerMain.class | Bin 0 -> 5331 bytes .../SyslogServerSessionEventHandlerIF.class | Bin 0 -> 829 bytes ...yslogServerSessionlessEventHandlerIF.class | Bin 0 -> 549 bytes .../impl/AbstractSyslogServer$Sessions.class | Bin 0 -> 2392 bytes .../server/impl/AbstractSyslogServer.class | Bin 0 -> 9368 bytes .../impl/AbstractSyslogServerConfig.class | Bin 0 -> 3073 bytes .../server/impl/event/SyslogServerEvent.class | Bin 0 -> 5420 bytes .../FileSyslogServerEventHandler.class | Bin 0 -> 1326 bytes .../PrintStreamSyslogServerEventHandler.class | Bin 0 -> 2868 bytes .../SystemErrSyslogServerEventHandler.class | Bin 0 -> 829 bytes .../SystemOutSyslogServerEventHandler.class | Bin 0 -> 829 bytes .../StructuredSyslogServerEvent.class | Bin 0 -> 3783 bytes .../net/AbstractNetSyslogServerConfig.class | Bin 0 -> 992 bytes ...slogServer$TCPNetSyslogSocketHandler.class | Bin 0 -> 3656 bytes .../impl/net/tcp/TCPNetSyslogServer.class | Bin 0 -> 5647 bytes .../net/tcp/TCPNetSyslogServerConfig.class | Bin 0 -> 2518 bytes .../net/tcp/TCPNetSyslogServerConfigIF.class | Bin 0 -> 631 bytes .../net/tcp/ssl/SSLTCPNetSyslogServer.class | Bin 0 -> 2029 bytes .../tcp/ssl/SSLTCPNetSyslogServerConfig.class | Bin 0 -> 1758 bytes .../ssl/SSLTCPNetSyslogServerConfigIF.class | Bin 0 -> 542 bytes .../impl/net/udp/UDPNetSyslogServer.class | Bin 0 -> 3674 bytes .../net/udp/UDPNetSyslogServerConfig.class | Bin 0 -> 1093 bytes .../syslog4j/util/Base64$InputStream.class | Bin 0 -> 2304 bytes .../syslog4j/util/Base64$OutputStream.class | Bin 0 -> 2519 bytes .../java/syslog4j/util/Base64.class | Bin 0 -> 17866 bytes .../java/syslog4j/util/OSDetectUtility.class | Bin 0 -> 1587 bytes .../java/syslog4j/util/SyslogUtility.class | Bin 0 -> 4774 bytes target/maven-archiver/pom.properties | 5 + target/syslog4j-graylog2-0.9.48-graylog2.jar | Bin 0 -> 163728 bytes 215 files changed, 11707 insertions(+) create mode 100644 README create mode 100644 pom.xml create mode 100644 src/main/java/org/productivity/java/syslog4j/Syslog.java create mode 100644 src/main/java/org/productivity/java/syslog4j/Syslog4jVersion.java create mode 100644 src/main/java/org/productivity/java/syslog4j/SyslogBackLogHandlerIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/SyslogCharSetIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/SyslogConfigIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/SyslogConstants.java create mode 100644 src/main/java/org/productivity/java/syslog4j/SyslogIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/SyslogMain.java create mode 100644 src/main/java/org/productivity/java/syslog4j/SyslogMessageIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/SyslogMessageModifierConfigIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/SyslogMessageModifierIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/SyslogMessageProcessorIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/SyslogPoolConfigIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/SyslogRuntimeException.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslog.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslogConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslogConfigIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslogWriter.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/backlog/AbstractSyslogBackLogHandler.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/backlog/NullSyslogBackLogHandler.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/backlog/Syslog4jBackLogHandler.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/backlog/log4j/Log4jSyslogBackLogHandler.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/backlog/printstream/PrintStreamSyslogBackLogHandler.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/backlog/printstream/SystemErrSyslogBackLogHandler.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/backlog/printstream/SystemOutSyslogBackLogHandler.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/log4j/Syslog4jAppender.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/log4j/Syslog4jAppenderSkeleton.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/AbstractSyslogMessage.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifier.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifierConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/checksum/ChecksumSyslogMessageModifier.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/checksum/ChecksumSyslogMessageModifierConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/escape/HTMLEntityEscapeSyslogMessageModifier.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/hash/HashSyslogMessageModifier.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/hash/HashSyslogMessageModifierConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/mac/MacSyslogMessageModifier.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/mac/MacSyslogMessageModifierConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifier.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifierConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/text/PrefixSyslogMessageModifier.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/text/StringCaseSyslogMessageModifier.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/modifier/text/SuffixSyslogMessageModifier.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/pci/PCISyslogMessage.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/pci/PCISyslogMessageIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/processor/AbstractSyslogMessageProcessor.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/processor/SyslogMessageProcessor.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/processor/structured/StructuredSyslogMessageProcessor.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessage.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessageIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/multiple/MultipleSyslog.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/multiple/MultipleSyslogConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/AbstractNetSyslog.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/AbstractNetSyslogConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/AbstractNetSyslogConfigIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslog.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogConfigIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogWriter.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslog.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslogConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslog.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogConfigIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogWriter.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/pool/PooledSSLTCPNetSyslogConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/udp/UDPNetSyslog.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/net/udp/UDPNetSyslogConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/pool/AbstractSyslogPoolFactory.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/pool/generic/GenericSyslogPoolFactory.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/unix/UnixSyslog.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/unix/UnixSyslogConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslog.java create mode 100644 src/main/java/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslogConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/SyslogServer.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/SyslogServerConfigIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/SyslogServerEventHandlerIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/SyslogServerEventIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/SyslogServerIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/SyslogServerMain.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/SyslogServerSessionEventHandlerIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/SyslogServerSessionlessEventHandlerIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/AbstractSyslogServer.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/AbstractSyslogServerConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/event/SyslogServerEvent.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/FileSyslogServerEventHandler.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/PrintStreamSyslogServerEventHandler.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/SystemErrSyslogServerEventHandler.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/SystemOutSyslogServerEventHandler.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/event/structured/StructuredSyslogServerEvent.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/net/AbstractNetSyslogServerConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServer.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfigIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServer.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServerConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServerConfigIF.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServer.java create mode 100644 src/main/java/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServerConfig.java create mode 100644 src/main/java/org/productivity/java/syslog4j/util/Base64.java create mode 100644 src/main/java/org/productivity/java/syslog4j/util/OSDetectUtility.java create mode 100644 src/main/java/org/productivity/java/syslog4j/util/SyslogUtility.java create mode 100644 target/classes/org/productivity/java/syslog4j/Syslog.class create mode 100644 target/classes/org/productivity/java/syslog4j/Syslog4jVersion.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogBackLogHandlerIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogCharSetIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogConfigIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogConstants.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogMain$Options.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogMain.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogMessageIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogMessageModifierConfigIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogMessageModifierIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogMessageProcessorIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogPoolConfigIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/SyslogRuntimeException.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/AbstractSyslog.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/AbstractSyslogConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/AbstractSyslogConfigIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/AbstractSyslogWriter.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/backlog/AbstractSyslogBackLogHandler.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/backlog/NullSyslogBackLogHandler.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/backlog/Syslog4jBackLogHandler.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/backlog/log4j/Log4jSyslogBackLogHandler.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/backlog/printstream/PrintStreamSyslogBackLogHandler.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/backlog/printstream/SystemErrSyslogBackLogHandler.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/backlog/printstream/SystemOutSyslogBackLogHandler.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/log4j/Syslog4jAppender.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/log4j/Syslog4jAppenderSkeleton.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/AbstractSyslogMessage.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifier.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifierConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/checksum/ChecksumSyslogMessageModifier.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/checksum/ChecksumSyslogMessageModifierConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/escape/HTMLEntityEscapeSyslogMessageModifier.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/hash/HashSyslogMessageModifier.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/hash/HashSyslogMessageModifierConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/mac/MacSyslogMessageModifier.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/mac/MacSyslogMessageModifierConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifier.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifierConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/text/PrefixSyslogMessageModifier.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/text/StringCaseSyslogMessageModifier.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/modifier/text/SuffixSyslogMessageModifier.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/pci/PCISyslogMessage.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/pci/PCISyslogMessageIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/processor/AbstractSyslogMessageProcessor.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/processor/SyslogMessageProcessor.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/processor/structured/StructuredSyslogMessageProcessor.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessage.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessageIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/multiple/MultipleSyslog.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/multiple/MultipleSyslogConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/AbstractNetSyslog.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/AbstractNetSyslogConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/AbstractNetSyslogConfigIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslog.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogConfigIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogWriter.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslog.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslogConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslog.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogConfigIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogWriter.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/tcp/ssl/pool/PooledSSLTCPNetSyslogConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/udp/UDPNetSyslog.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/net/udp/UDPNetSyslogConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/pool/AbstractSyslogPoolFactory.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/pool/generic/GenericSyslogPoolFactory.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/unix/UnixSyslog$CLibrary.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/unix/UnixSyslog.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/unix/UnixSyslogConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslog$CLibrary.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslog$SockAddr.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslog.class create mode 100644 target/classes/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslogConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/SyslogServer.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/SyslogServerConfigIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/SyslogServerEventHandlerIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/SyslogServerEventIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/SyslogServerIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/SyslogServerMain$Options.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/SyslogServerMain.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/SyslogServerSessionEventHandlerIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/SyslogServerSessionlessEventHandlerIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/AbstractSyslogServer$Sessions.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/AbstractSyslogServer.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/AbstractSyslogServerConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/event/SyslogServerEvent.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/event/printstream/FileSyslogServerEventHandler.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/event/printstream/PrintStreamSyslogServerEventHandler.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/event/printstream/SystemErrSyslogServerEventHandler.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/event/printstream/SystemOutSyslogServerEventHandler.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/event/structured/StructuredSyslogServerEvent.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/net/AbstractNetSyslogServerConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServer$TCPNetSyslogSocketHandler.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServer.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfigIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServer.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServerConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServerConfigIF.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServer.class create mode 100644 target/classes/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServerConfig.class create mode 100644 target/classes/org/productivity/java/syslog4j/util/Base64$InputStream.class create mode 100644 target/classes/org/productivity/java/syslog4j/util/Base64$OutputStream.class create mode 100644 target/classes/org/productivity/java/syslog4j/util/Base64.class create mode 100644 target/classes/org/productivity/java/syslog4j/util/OSDetectUtility.class create mode 100644 target/classes/org/productivity/java/syslog4j/util/SyslogUtility.class create mode 100644 target/maven-archiver/pom.properties create mode 100644 target/syslog4j-graylog2-0.9.48-graylog2.jar diff --git a/README b/README new file mode 100644 index 0000000..63ca26a --- /dev/null +++ b/README @@ -0,0 +1 @@ +The syslog4j fork from Graylog2. This is used since 0.10.0. The original code was very "special" and no actions were taken to improve it. This is planned to be replaced completely in future versions. \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..05c9175 --- /dev/null +++ b/pom.xml @@ -0,0 +1,48 @@ + + 4.0.0 + + org.productivity.java + syslog4j-graylog2 + 0.9.48-graylog2 + jar + + syslog4j-graylog2 + http://maven.apache.org + + + UTF-8 + + + + + joda-time + joda-time + 1.6.2 + + + commons-pool + commons-pool + 1.5.4 + true + + + log4j + log4j + 1.2.14 + true + + + com.sun.jna + jna + 3.0.9 + true + + + junit + junit + 3.8.1 + test + + + diff --git a/src/main/java/org/productivity/java/syslog4j/Syslog.java b/src/main/java/org/productivity/java/syslog4j/Syslog.java new file mode 100644 index 0000000..23681bb --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/Syslog.java @@ -0,0 +1,318 @@ +package org.productivity.java.syslog4j; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslogConfig; +import org.productivity.java.syslog4j.impl.net.udp.UDPNetSyslogConfig; +import org.productivity.java.syslog4j.impl.unix.UnixSyslogConfig; +import org.productivity.java.syslog4j.impl.unix.socket.UnixSocketSyslogConfig; +import org.productivity.java.syslog4j.util.OSDetectUtility; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** + * This class provides a Singleton interface for Syslog4j client implementations. + * + *

Usage examples:

+ * + * Direct + *
+ * Syslog.getInstance("udp").info("log message");
+ * 
+ * + * Via Instance + *
+ * SyslogIF syslog = Syslog.getInstance("udp");
+ * syslog.info();
+ * 
+ * + *

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy + * of the LGPL license is available in the META-INF folder in all + * distributions of Syslog4j and in the base directory of the "doc" ZIP.

+ * + * @author <syslog4j@productivity.org> + * @version $Id: Syslog.java,v 1.23 2011/01/23 20:49:12 cvs Exp $ + */ +public final class Syslog implements SyslogConstants { + private static final long serialVersionUID = -4662318148650646144L; + + private static boolean SUPPRESS_RUNTIME_EXCEPTIONS = false; + + protected static final Map instances = new Hashtable(); + + static { + initialize(); + } + + /** + * Syslog is a singleton. + */ + private Syslog() { + // + } + + /** + * @return Returns the current version identifier for Syslog4j. + */ + public static final String getVersion() { + return Syslog4jVersion.VERSION; + } + + /** + * @param suppress - true to suppress throwing SyslogRuntimeException in many methods of this class, false to throw exceptions (default) + */ + public static void setSuppressRuntimeExceptions(boolean suppress) { + SUPPRESS_RUNTIME_EXCEPTIONS = suppress; + } + + /** + * @return Returns whether or not to suppress throwing SyslogRuntimeException in many methods of this class. + */ + public static boolean getSuppressRuntimeExceptions() { + return SUPPRESS_RUNTIME_EXCEPTIONS; + } + + /** + * Throws SyslogRuntimeException unless it has been suppressed via setSuppressRuntimeException(boolean). + * + * @param message + * @throws SyslogRuntimeException + */ + private static void throwRuntimeException(String message) throws SyslogRuntimeException { + if (SUPPRESS_RUNTIME_EXCEPTIONS) { + return; + + } else { + throw new SyslogRuntimeException(message.toString()); + } + } + + /** + * Use getInstance(protocol) as the starting point for Syslog4j. + * + * @param protocol - the Syslog protocol to use, e.g. "udp", "tcp", "unix_syslog", "unix_socket", or a custom protocol + * @return Returns an instance of SyslogIF. + * @throws SyslogRuntimeException + */ + public static final SyslogIF getInstance(String protocol) throws SyslogRuntimeException { + String _protocol = protocol.toLowerCase(); + + if (instances.containsKey(_protocol)) { + return (SyslogIF) instances.get(_protocol); + + } else { + StringBuffer message = new StringBuffer("Syslog protocol \"" + protocol + "\" not defined; call Syslogger.createSyslogInstance(protocol,config) first"); + + if (instances.size() > 0) { + message.append(" or use one of the following instances: "); + + Iterator i = instances.keySet().iterator(); + while (i.hasNext()) { + String k = (String) i.next(); + + message.append(k); + if (i.hasNext()) { + message.append(' '); + } + } + } + + throwRuntimeException(message.toString()); + return null; + } + } + + /** + * Use createInstance(protocol,config) to create your own Syslog instance. + * + *

First, create an implementation of SyslogConfigIF, such as UdpNetSyslogConfig.

+ * + *

Second, configure that configuration instance.

+ * + *

Third, call createInstance(protocol,config) using a short & simple + * String for the protocol argument.

+ * + *

Fourth, either use the returned instance of SyslogIF, or in later code + * call getInstance(protocol) with the protocol chosen in the previous step.

+ * + * @param protocol + * @param config + * @return Returns an instance of SyslogIF. + * @throws SyslogRuntimeException + */ + public static final SyslogIF createInstance(String protocol, SyslogConfigIF config) throws SyslogRuntimeException { + if (protocol == null || "".equals(protocol.trim())) { + throwRuntimeException("Instance protocol cannot be null or empty"); + return null; + } + + if (config == null) { + throwRuntimeException("SyslogConfig cannot be null"); + return null; + } + + String syslogProtocol = protocol.toLowerCase(); + + SyslogIF syslog = null; + + synchronized(instances) { + if (instances.containsKey(syslogProtocol)) { + throwRuntimeException("Syslog protocol \"" + protocol + "\" already defined"); + return null; + } + + try { + Class syslogClass = config.getSyslogClass(); + + syslog = (SyslogIF) syslogClass.newInstance(); + + } catch (ClassCastException cse) { + if (!config.isThrowExceptionOnInitialize()) { + throw new SyslogRuntimeException(cse); + + } else { + return null; + } + + } catch (IllegalAccessException iae) { + if (!config.isThrowExceptionOnInitialize()) { + throw new SyslogRuntimeException(iae); + + } else { + return null; + } + + } catch (InstantiationException ie) { + if (!config.isThrowExceptionOnInitialize()) { + throw new SyslogRuntimeException(ie); + + } else { + return null; + } + } + + syslog.initialize(syslogProtocol,config); + + instances.put(syslogProtocol,syslog); + } + + return syslog; + } + + /** + * initialize() sets up the default TCP and UDP Syslog protocols, as + * well as UNIX_SYSLOG and UNIX_SOCKET (if running on a Unix-based system). + */ + public synchronized static final void initialize() { + createInstance(UDP,new UDPNetSyslogConfig()); + createInstance(TCP,new TCPNetSyslogConfig()); + + if (OSDetectUtility.isUnix() && SyslogUtility.isClassExists(JNA_NATIVE_CLASS)) { + createInstance(UNIX_SYSLOG,new UnixSyslogConfig()); + createInstance(UNIX_SOCKET,new UnixSocketSyslogConfig()); + } + } + + /** + * @param protocol - Syslog protocol + * @return Returns whether the protocol has been previously defined. + */ + public static final boolean exists(String protocol) { + if (protocol == null || "".equals(protocol.trim())) { + return false; + } + + return instances.containsKey(protocol.toLowerCase()); + } + + /** + * shutdown() gracefully shuts down all defined Syslog protocols, + * which includes flushing all queues and connections and finally + * clearing all instances (including those initialized by default). + */ + public synchronized static final void shutdown() { + Set protocols = instances.keySet(); + + if (protocols.size() > 0) { + Iterator i = protocols.iterator(); + + SyslogUtility.sleep(SyslogConstants.THREAD_LOOP_INTERVAL_DEFAULT); + + while(i.hasNext()) { + String protocol = (String) i.next(); + + SyslogIF syslog = (SyslogIF) instances.get(protocol); + + syslog.shutdown(); + } + + instances.clear(); + } + } + + /** + * destroyInstance() gracefully shuts down the specified Syslog protocol and + * removes the instance from Syslog4j. + * + * @param protocol - the Syslog protocol to destroy + * @throws SyslogRuntimeException + */ + public synchronized static final void destroyInstance(String protocol) throws SyslogRuntimeException { + if (protocol == null || "".equals(protocol.trim())) { + return; + } + + String _protocol = protocol.toLowerCase(); + + if (instances.containsKey(_protocol)) { + SyslogUtility.sleep(SyslogConstants.THREAD_LOOP_INTERVAL_DEFAULT); + + SyslogIF syslog = (SyslogIF) instances.get(_protocol); + + try { + syslog.shutdown(); + + } finally { + instances.remove(_protocol); + } + + } else { + throwRuntimeException("Cannot destroy protocol \"" + protocol + "\" instance; call shutdown instead"); + return; + } + } + + /** + * destroyInstance() gracefully shuts down the specified Syslog instance and + * removes it from Syslog4j. + * + * @param syslog - the Syslog instance to destroy + * @throws SyslogRuntimeException + */ + public synchronized static final void destroyInstance(SyslogIF syslog) throws SyslogRuntimeException { + if (syslog == null) { + return; + } + + String protocol = syslog.getProtocol().toLowerCase(); + + if (instances.containsKey(protocol)) { + try { + syslog.shutdown(); + + } finally { + instances.remove(protocol); + } + + } else { + throwRuntimeException("Cannot destroy protocol \"" + protocol + "\" instance; call shutdown instead"); + return; + } + } + + public static void main(String[] args) throws Exception { + SyslogMain.main(args); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/Syslog4jVersion.java b/src/main/java/org/productivity/java/syslog4j/Syslog4jVersion.java new file mode 100644 index 0000000..077855d --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/Syslog4jVersion.java @@ -0,0 +1,16 @@ +package org.productivity.java.syslog4j; + +/** +* Syslog4jVersion provides a unique version identifier that is created during +* the build process. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: Syslog4jVersion.java,v 1.2 2008/10/28 01:07:06 cvs Exp $ +*/ +public final class Syslog4jVersion { + public static final String VERSION = "Syslog4j 0.9.46 2011-01-23 14:49:24 jpy"; +} diff --git a/src/main/java/org/productivity/java/syslog4j/SyslogBackLogHandlerIF.java b/src/main/java/org/productivity/java/syslog4j/SyslogBackLogHandlerIF.java new file mode 100644 index 0000000..d88a5c6 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/SyslogBackLogHandlerIF.java @@ -0,0 +1,51 @@ +package org.productivity.java.syslog4j; + +/** +* SyslogBackLogHandlerIF provides a last-chance mechanism to log messages that fail +* (for whatever reason) within the rest of Syslog. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +*

Implementing the down(SyslogIF) method is an excellent way to add some sort of notification to +* your application when a Syslog service is unavailable.

+* +*

Implementing the up(SyslogIF) method can be used to notify your application when a Syslog +* service has returned.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogBackLogHandlerIF.java,v 1.2 2009/01/28 15:13:52 cvs Exp $ +*/ +public interface SyslogBackLogHandlerIF { + /** + * Implement initialize() to handle one-time set-up for this backLog handler. + * + * @throws SyslogRuntimeException + */ + public void initialize() throws SyslogRuntimeException; + + /** + * Implement down(syslog,reason) to notify/log when the syslog protocol is unavailable. + * + * @param syslog - SyslogIF instance causing this down condition + * @param reason - reason given for the down condition + */ + public void down(SyslogIF syslog, String reason); + + /** + * Implement up(syslog) to notify/log when the syslog protocol becomes available after a down condition. + * + * @param syslog - SyslogIF instance which is now available + */ + public void up(SyslogIF syslog); + + /** + * @param syslog - SyslogIF instance which cannot handle this log event + * @param level - message level + * @param message - message (in String form) + * @param reason - reason given for why this message could not be handled + * @throws SyslogRuntimeException - throwing this Exception activates the next backlogHandler in the chain + */ + public void log(SyslogIF syslog, int level, String message, String reason) throws SyslogRuntimeException; +} diff --git a/src/main/java/org/productivity/java/syslog4j/SyslogCharSetIF.java b/src/main/java/org/productivity/java/syslog4j/SyslogCharSetIF.java new file mode 100644 index 0000000..62a6bb6 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/SyslogCharSetIF.java @@ -0,0 +1,19 @@ +package org.productivity.java.syslog4j; + +import java.io.Serializable; + +/** +* SyslogCharSetIF provides control of the encoding character set within +* several class of Syslog4j. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogCharSetIF.java,v 1.3 2008/11/07 15:15:41 cvs Exp $ +*/ +public interface SyslogCharSetIF extends Serializable { + public String getCharSet(); + public void setCharSet(String charSet); +} diff --git a/src/main/java/org/productivity/java/syslog4j/SyslogConfigIF.java b/src/main/java/org/productivity/java/syslog4j/SyslogConfigIF.java new file mode 100644 index 0000000..ac4ed64 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/SyslogConfigIF.java @@ -0,0 +1,69 @@ +package org.productivity.java.syslog4j; + +/** +* SyslogConfigIF provides a common, extensible configuration interface for all +* implementations of SyslogIF. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogConfigIF.java,v 1.19 2010/11/28 04:15:18 cvs Exp $ +*/ +public interface SyslogConfigIF extends SyslogConstants, SyslogCharSetIF { + public Class getSyslogClass(); + + public int getFacility(); + public void setFacility(int facility); + public void setFacility(String facilityName); + + public int getPort(); + public void setPort(int port) throws SyslogRuntimeException; + + public String getLocalName(); + public void setLocalName(String localName) throws SyslogRuntimeException; + + public String getHost(); + public void setHost(String host) throws SyslogRuntimeException; + + public String getIdent(); + public void setIdent(String ident); + + public String getCharSet(); + public void setCharSet(String charSet); + + public boolean isIncludeIdentInMessageModifier(); + public void setIncludeIdentInMessageModifier(boolean throwExceptionOnInitialize); + + public boolean isThrowExceptionOnInitialize(); + public void setThrowExceptionOnInitialize(boolean throwExceptionOnInitialize); + + public boolean isThrowExceptionOnWrite(); + public void setThrowExceptionOnWrite(boolean throwExceptionOnWrite); + + public boolean isSendLocalTimestamp(); + public void setSendLocalTimestamp(boolean sendLocalTimestamp); + + public boolean isSendLocalName(); + public void setSendLocalName(boolean sendLocalName); + + public boolean isTruncateMessage(); + public void setTruncateMessage(boolean truncateMessage); + + public boolean isUseStructuredData(); + public void setUseStructuredData(boolean useStructuredData); + + public int getMaxMessageLength(); + public void setMaxMessageLength(int maxMessageLength); + + public void addMessageModifier(SyslogMessageModifierIF messageModifier); + public void insertMessageModifier(int index, SyslogMessageModifierIF messageModifier); + public void removeMessageModifier(SyslogMessageModifierIF messageModifier); + public void removeAllMessageModifiers(); + + public void addBackLogHandler(SyslogBackLogHandlerIF backLogHandler); + public void insertBackLogHandler(int index, SyslogBackLogHandlerIF backLogHandler); + public void removeBackLogHandler(SyslogBackLogHandlerIF backLogHandler); + public void removeAllBackLogHandlers(); +} diff --git a/src/main/java/org/productivity/java/syslog4j/SyslogConstants.java b/src/main/java/org/productivity/java/syslog4j/SyslogConstants.java new file mode 100644 index 0000000..175f4e8 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/SyslogConstants.java @@ -0,0 +1,164 @@ +package org.productivity.java.syslog4j; + +import java.io.Serializable; + +/** +* SyslogConstants provides several global constant values for several +* classes within Syslog4j. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogConstants.java,v 1.33 2011/01/11 05:11:13 cvs Exp $ +*/ +public interface SyslogConstants extends Serializable { + public static final String SYSLOG_PATH_DEFAULT = "/dev/log"; + public static final String SYSLOG_HOST_DEFAULT = "localhost"; + public static final int SYSLOG_PORT_DEFAULT = 514; + public static final int SYSLOG_BUFFER_SIZE = 1024; + public static final int SERVER_SOCKET_BACKLOG_DEFAULT = 50; + + public static final String SYSLOG_DATEFORMAT = "MMM dd HH:mm:ss "; + + public static final String STRUCTURED_DATA_NILVALUE = "-"; + public static final String STRUCTURED_DATA_EMPTY_VALUE = "[0@0]"; + + public static final String CHAR_SET_DEFAULT = "UTF-8"; + + public static final byte[] LF = "\n".getBytes(); + public static final byte[] CRLF = "\r\n".getBytes(); + + public static final byte[] TCP_DELIMITER_SEQUENCE_DEFAULT = LF; + + public static final boolean THREADED_DEFAULT = true; + public static final long THREAD_LOOP_INTERVAL_DEFAULT = 500; + + public static final boolean SEND_LOCAL_NAME_DEFAULT = true; + public static final boolean SEND_LOCAL_TIMESTAMP_DEFAULT = true; + public static final boolean CACHE_HOST_ADDRESS_DEFAULT = true; + + public static final int MAX_MESSAGE_LENGTH_DEFAULT = 1024; + + public static final boolean INCLUDE_IDENT_IN_MESSAGE_MODIFIER_DEFAULT = false; + public static final boolean THROW_EXCEPTION_ON_INITIALIZE_DEFAULT = true; + public static final boolean THROW_EXCEPTION_ON_WRITE_DEFAULT = false; + public static final boolean USE_STRUCTURED_DATA_DEFAULT = false; + public static final String STRUCTURED_DATA_APP_NAME_DEFAULT_VALUE = "unknown"; + public static final String STRUCTURED_DATA_PROCESS_ID_DEFAULT_VALUE = STRUCTURED_DATA_NILVALUE; + + public static final boolean USE_DAEMON_THREAD_DEFAULT = true; + public static final int THREAD_PRIORITY_DEFAULT = -1; + + public static final boolean TRUNCATE_MESSAGE_DEFAULT = false; + + public static final String SPLIT_MESSAGE_BEGIN_TEXT_DEFAULT = "..."; + public static final String SPLIT_MESSAGE_END_TEXT_DEFAULT = "..."; + + public static final String SEND_LOCAL_NAME_DEFAULT_VALUE = "unknown"; + + public static final String TCP = "tcp"; + public static final String UDP = "udp"; + public static final String UNIX_SYSLOG = "unix_syslog"; + public static final String UNIX_SOCKET = "unix_socket"; + + public static final boolean TCP_PERSISTENT_CONNECTION_DEFAULT = true; + public static final boolean TCP_SO_LINGER_DEFAULT = true; + public static final int TCP_SO_LINGER_SECONDS_DEFAULT = 1; + public static final boolean TCP_KEEP_ALIVE_DEFAULT = true; + public static final boolean TCP_REUSE_ADDRESS_DEFAULT = true; + public static final boolean TCP_SET_BUFFER_SIZE_DEFAULT = true; + public static final int TCP_FRESH_CONNECTION_INTERVAL_DEFAULT = -1; + + public static final int TCP_MAX_ACTIVE_SOCKETS_DEFAULT = 0; + public static final byte TCP_MAX_ACTIVE_SOCKETS_BEHAVIOR_DEFAULT = 0; + + public static final int FACILITY_KERN = 0; + public static final int FACILITY_USER = 1<<3; + public static final int FACILITY_MAIL = 2<<3; + public static final int FACILITY_DAEMON = 3<<3; + public static final int FACILITY_AUTH = 4<<3; + public static final int FACILITY_SYSLOG = 5<<3; + + public static final int FACILITY_LPR = 6<<3; + public static final int FACILITY_NEWS = 7<<3; + public static final int FACILITY_UUCP = 8<<3; + public static final int FACILITY_CRON = 9<<3; + public static final int FACILITY_AUTHPRIV = 10<<3; + public static final int FACILITY_FTP = 11<<3; + + public static final int FACILITY_LOCAL0 = 16<<3; + public static final int FACILITY_LOCAL1 = 17<<3; + public static final int FACILITY_LOCAL2 = 18<<3; + public static final int FACILITY_LOCAL3 = 19<<3; + public static final int FACILITY_LOCAL4 = 20<<3; + public static final int FACILITY_LOCAL5 = 21<<3; + public static final int FACILITY_LOCAL6 = 22<<3; + public static final int FACILITY_LOCAL7 = 23<<3; + + public static final int SYSLOG_FACILITY_DEFAULT = FACILITY_USER; + + public static final int LEVEL_DEBUG = 7; + public static final int LEVEL_INFO = 6; + public static final int LEVEL_NOTICE = 5; + public static final int LEVEL_WARN = 4; + public static final int LEVEL_ERROR = 3; + public static final int LEVEL_CRITICAL = 2; + public static final int LEVEL_ALERT = 1; + public static final int LEVEL_EMERGENCY = 0; + + public static final int OPTION_NONE = 0; + public static final int OPTION_LOG_CONS = 1; + public static final int OPTION_LOG_NDELAY = 2; + public static final int OPTION_LOG_NOWAIT = 4; + public static final int OPTION_LOG_ODELAY = 8; + public static final int OPTION_LOG_PERROR = 16; + public static final int OPTION_LOG_PID = 32; + + public static final int SOCK_STREAM = 1; + public static final int SOCK_DGRAM = 2; + + public static final short AF_UNIX = 1; + + public static final int WRITE_RETRIES_DEFAULT = 2; + public static final int MAX_SHUTDOWN_WAIT_DEFAULT = 30000; + public static final long SHUTDOWN_INTERVAL = 100; + public static final int MAX_QUEUE_SIZE_DEFAULT = -1; + + public static final long SERVER_SHUTDOWN_WAIT_DEFAULT = 500; + + public static final String SYSLOG_LIBRARY_DEFAULT = "c"; + + public static final int SYSLOG_SOCKET_TYPE_DEFAULT = SOCK_DGRAM; + public static final short SYSLOG_SOCKET_FAMILY_DEFAULT = AF_UNIX; + public static final String SYSLOG_SOCKET_LIBRARY_DEFAULT = "c"; + public static final int SYSLOG_SOCKET_PROTOCOL_DEFAULT = 0; + public static final String SYSLOG_SOCKET_PATH_DEFAULT = "/dev/log"; + + public static final String JNA_NATIVE_CLASS = "com.sun.jna.Native"; + + public static final String IDENT_SUFFIX_DEFAULT = ": "; + + public static final String SYSLOG_MESSAGE_MODIFIER_PREFIX_DEFAULT = " {"; + public static final String SYSLOG_MESSAGE_MODIFIER_SUFFIX_DEFAULT = "}"; + + public static final String SYSLOG_SEQUENTIAL_MESSAGE_MODIFIER_PREFIX_DEFAULT = " #"; + public static final String SYSLOG_SEQUENTIAL_MESSAGE_MODIFIER_SUFFIX_DEFAULT = ""; + public static final long SYSLOG_SEQUENTIAL_MESSAGE_MODIFIER_FIRST_NUMBER_DEFAULT = 0; + public static final long SYSLOG_SEQUENTIAL_MESSAGE_MODIFIER_LAST_NUMBER_DEFAULT = 9999; + public static final char SYSLOG_SEQUENTIAL_MESSAGE_MODIFIER_PAD_CHAR_DEFAULT = '0'; + public static final boolean SYSLOG_SEQUENTIAL_MESSAGE_MODIFIER_USE_PADDING_DEFAULT = true; + + public static final int SYSLOG_POOL_CONFIG_MAX_ACTIVE_DEFAULT = 4; + public static final int SYSLOG_POOL_CONFIG_MAX_IDLE_DEFAULT = 4; + public static final int SYSLOG_POOL_CONFIG_MAX_WAIT_DEFAULT = 1000; + public static final int SYSLOG_POOL_CONFIG_NUM_TESTS_PER_EVICTION_RUN_DEFAULT = 0; + public static final int SYSLOG_POOL_CONFIG_MIN_IDLE_DEFAULT = 4; + public static final int SYSLOG_POOL_CONFIG_MIN_EVICTABLE_IDLE_TIME_MILLIS_DEFAULT = 0; + public static final int SYSLOG_POOL_CONFIG_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS_DEFAULT = 0; + public static final int SYSLOG_POOL_CONFIG_TIME_BETWEEN_EVICTION_RUNS_MILLIS_DEFAULT = 0; + public static final boolean SYSLOG_POOL_CONFIG_TEST_ON_BORROW_DEFAULT = false; + public static final boolean SYSLOG_POOL_CONFIG_TEST_ON_RETURN_DEFAULT = false; + public static final boolean SYSLOG_POOL_CONFIG_TEST_WHILE_IDLE_DEFAULT = false; +} diff --git a/src/main/java/org/productivity/java/syslog4j/SyslogIF.java b/src/main/java/org/productivity/java/syslog4j/SyslogIF.java new file mode 100644 index 0000000..b69a995 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/SyslogIF.java @@ -0,0 +1,52 @@ +package org.productivity.java.syslog4j; + +/** +* SyslogIF provides a common interface for all Syslog4j client implementations. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogIF.java,v 1.9 2010/02/11 04:59:22 cvs Exp $ +*/ +public interface SyslogIF extends SyslogConstants { + public void initialize(String protocol, SyslogConfigIF config) throws SyslogRuntimeException; + + public String getProtocol(); + public SyslogConfigIF getConfig(); + + public void backLog(int level, String message, Throwable reasonThrowable); + public void backLog(int level, String message, String reason); + + public void log(int level, String message); + + public void debug(String message); + public void info(String message); + public void notice(String message); + public void warn(String message); + public void error(String message); + public void critical(String message); + public void alert(String message); + public void emergency(String message); + + public void log(int level, SyslogMessageIF message); + + public void debug(SyslogMessageIF message); + public void info(SyslogMessageIF message); + public void notice(SyslogMessageIF message); + public void warn(SyslogMessageIF message); + public void error(SyslogMessageIF message); + public void critical(SyslogMessageIF message); + public void alert(SyslogMessageIF message); + public void emergency(SyslogMessageIF message); + + public void flush() throws SyslogRuntimeException; + public void shutdown() throws SyslogRuntimeException; + + public void setMessageProcessor(SyslogMessageProcessorIF messageProcessor); + public SyslogMessageProcessorIF getMessageProcessor(); + + public void setStructuredMessageProcessor(SyslogMessageProcessorIF messageProcessor); + public SyslogMessageProcessorIF getStructuredMessageProcessor(); +} diff --git a/src/main/java/org/productivity/java/syslog4j/SyslogMain.java b/src/main/java/org/productivity/java/syslog4j/SyslogMain.java new file mode 100644 index 0000000..69a6e51 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/SyslogMain.java @@ -0,0 +1,198 @@ +package org.productivity.java.syslog4j; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; + +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** + * This class provides a command-line interface for Syslog4j + * server implementations. + * + *

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy + * of the LGPL license is available in the META-INF folder in all + * distributions of Syslog4j and in the base directory of the "doc" ZIP.

+ * + * @author <syslog4j@productivity.org> + * @version $Id: SyslogMain.java,v 1.4 2010/11/28 01:38:08 cvs Exp $ + */ +public class SyslogMain { + public static boolean CALL_SYSTEM_EXIT_ON_FAILURE = true; + + public static class Options { + public String host = null; + public String port = null; + public String level = "INFO"; + public String facility = "USER"; + public String protocol = null; + public String message = null; + public String fileName = null; + + public boolean quiet = false; + + public String usage = null; + } + + public static void usage(String problem) { + if (problem != null) { + System.out.println("Error: " + problem); + System.out.println(); + } + + System.out.println("Usage:"); + System.out.println(); + System.out.println("Syslog [-h ] [-p ] [-l ] [-f ]"); + System.out.println(" "); + System.out.println(); + System.out.println("Syslog [-h ] [-p ] [-l ] [-f ]"); + System.out.println(" [message...]"); + System.out.println(); + System.out.println("Syslog [-h ] [-p ] [-l ] [-f ]"); + System.out.println(" -i "); + System.out.println(); + System.out.println("-h host or IP to send message (default: localhost)"); + System.out.println("-p port to send message (default: 514)"); + System.out.println("-l syslog level to use (default: INFO)"); + System.out.println("-f syslog facility to use (default: USER)"); + System.out.println("-i input taken from the specified file"); + System.out.println(); + System.out.println("-q do not write anything to standard out"); + System.out.println(); + System.out.println("protocol Syslog4j protocol implementation"); + System.out.println("message syslog message text"); + System.out.println(); + System.out.println("Notes:"); + System.out.println(); + System.out.println("Additional message arguments will be concatenated into the same"); + System.out.println("syslog message; calling SyslogMain will only send one message per call."); + System.out.println(); + System.out.println("If the message argument is ommited, lines will be taken from the"); + System.out.println("standard input."); + } + + public static Options parseOptions(String[] args) { + Options options = new Options(); + + int i = 0; + while(i < args.length) { + String arg = args[i++]; + boolean match = false; + + if ("-h".equals(arg)) { if (i == args.length) { options.usage = "Must specify host with -h"; return options; } match = true; options.host = args[i++]; } + if ("-p".equals(arg)) { if (i == args.length) { options.usage = "Must specify port with -p"; return options; } match = true; options.port = args[i++]; } + if ("-l".equals(arg)) { if (i == args.length) { options.usage = "Must specify level with -l"; return options; } match = true; options.level = args[i++]; } + if ("-f".equals(arg)) { if (i == args.length) { options.usage = "Must specify facility with -f"; return options; } match = true; options.facility = args[i++]; } + if ("-i".equals(arg)) { if (i == args.length) { options.usage = "Must specify file with -i"; return options; } match = true; options.fileName = args[i++]; } + + if ("-q".equals(arg)) { match = true; options.quiet = true; } + + if (options.protocol == null && !match) { + match = true; + options.protocol = arg; + } + + if (!match) { + if (options.message == null) { + options.message = arg; + + } else { + options.message += " " + arg; + } + } + } + + if (options.protocol == null) { + options.usage = "Must specify protocol"; + return options; + } + + if (options.message != null && options.fileName != null) { + options.usage = "Must specify either -i or , not both"; + return options; + } + + return options; + } + + public static void main(String[] args) throws Exception { + main(args,true); + } + + public static void main(String[] args, boolean shutdown) throws Exception { + Options options = parseOptions(args); + + if (options.usage != null) { + usage(options.usage); + if (CALL_SYSTEM_EXIT_ON_FAILURE) { System.exit(1); } else { return; } + } + + if (!options.quiet) { + System.out.println("Syslog " + Syslog.getVersion()); + } + + if (!Syslog.exists(options.protocol)) { + usage("Protocol \"" + options.protocol + "\" not supported"); + if (CALL_SYSTEM_EXIT_ON_FAILURE) { System.exit(1); } else { return; } + } + + SyslogIF syslog = Syslog.getInstance(options.protocol); + + SyslogConfigIF syslogConfig = syslog.getConfig(); + + if (options.host != null) { + syslogConfig.setHost(options.host); + if (!options.quiet) { + System.out.println("Sending to host: " + options.host); + } + } + + if (options.port != null) { + syslogConfig.setPort(Integer.parseInt(options.port)); + if (!options.quiet) { + System.out.println("Sending to port: " + options.port); + } + } + + int level = SyslogUtility.getLevel(options.level); + + syslogConfig.setFacility(options.facility); + + if (options.message != null) { + if (!options.quiet) { + System.out.println("Sending " + options.facility + "." + options.level + " message \"" + options.message + "\""); + } + + syslog.log(level,options.message); + + } else { + InputStream is = null; + + if (options.fileName != null) { + is = new FileInputStream(options.fileName); + + } else { + is = System.in; + } + + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + + String line = br.readLine(); + + while(line != null && line.length() > 0) { + if (!options.quiet) { + System.out.println("Sending " + options.facility + "." + options.level + " message \"" + line + "\""); + } + + syslog.log(level,line); + + line = br.readLine(); + } + } + + if (shutdown) { + Syslog.shutdown(); + } + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/SyslogMessageIF.java b/src/main/java/org/productivity/java/syslog4j/SyslogMessageIF.java new file mode 100644 index 0000000..0007a94 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/SyslogMessageIF.java @@ -0,0 +1,17 @@ +package org.productivity.java.syslog4j; + +import java.io.Serializable; + +/** +* SyslogMessageIF provides a common interface for all Syslog4j event implementations. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogMessageIF.java,v 1.1 2008/11/10 04:38:37 cvs Exp $ +*/ +public interface SyslogMessageIF extends Serializable { + public String createMessage(); +} diff --git a/src/main/java/org/productivity/java/syslog4j/SyslogMessageModifierConfigIF.java b/src/main/java/org/productivity/java/syslog4j/SyslogMessageModifierConfigIF.java new file mode 100644 index 0000000..08e51ab --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/SyslogMessageModifierConfigIF.java @@ -0,0 +1,20 @@ +package org.productivity.java.syslog4j; + +/** +* SyslogMessageModifierConfigIF provides a common configuration interface for all +* Syslog4j message modifier implementations. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogMessageModifierConfigIF.java,v 1.3 2010/10/28 05:10:57 cvs Exp $ +*/ +public interface SyslogMessageModifierConfigIF extends SyslogConstants, SyslogCharSetIF { + public String getPrefix(); + public void setPrefix(String prefix); + + public String getSuffix(); + public void setSuffix(String suffix); +} diff --git a/src/main/java/org/productivity/java/syslog4j/SyslogMessageModifierIF.java b/src/main/java/org/productivity/java/syslog4j/SyslogMessageModifierIF.java new file mode 100644 index 0000000..4d68756 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/SyslogMessageModifierIF.java @@ -0,0 +1,17 @@ +package org.productivity.java.syslog4j; + +/** +* SyslogMessageModifierIF provides a common interface for all +* Syslog4j message modifier implementations. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogMessageModifierIF.java,v 1.4 2010/10/28 05:10:57 cvs Exp $ +*/ +public interface SyslogMessageModifierIF extends SyslogConstants { + public String modify(SyslogIF syslog, int facility, int level, String message); + public boolean verify(String message); +} diff --git a/src/main/java/org/productivity/java/syslog4j/SyslogMessageProcessorIF.java b/src/main/java/org/productivity/java/syslog4j/SyslogMessageProcessorIF.java new file mode 100644 index 0000000..c886dd8 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/SyslogMessageProcessorIF.java @@ -0,0 +1,22 @@ +package org.productivity.java.syslog4j; + +import java.io.Serializable; + +/** +* SyslogMessageProcessorIF provides an extensible interface for writing custom +* Syslog4j message processors. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogMessageProcessorIF.java,v 1.4 2010/11/28 04:15:18 cvs Exp $ +*/ +public interface SyslogMessageProcessorIF extends Serializable { + public String createSyslogHeader(int facility, int level, String localName, boolean sendLocalTimestamp, boolean sendLocalName); + + public byte[] createPacketData(byte[] header, byte[] message, int start, int length); + + public byte[] createPacketData(byte[] header, byte[] message, int start, int length, byte[] splitBeginText, byte[] splitEndText); +} diff --git a/src/main/java/org/productivity/java/syslog4j/SyslogPoolConfigIF.java b/src/main/java/org/productivity/java/syslog4j/SyslogPoolConfigIF.java new file mode 100644 index 0000000..18c4404 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/SyslogPoolConfigIF.java @@ -0,0 +1,52 @@ +package org.productivity.java.syslog4j; + +import java.io.Serializable; + +/** +* SyslogPoolConfigIF is an interface which provides configuration support +* for the Apache Commons Pool. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogPoolConfigIF.java,v 1.2 2009/03/29 17:38:58 cvs Exp $ +*/ +public interface SyslogPoolConfigIF extends Serializable { + public int getMaxActive(); + public void setMaxActive(int maxActive); + + public int getMaxIdle(); + public void setMaxIdle(int maxIdle); + + public long getMaxWait(); + public void setMaxWait(long maxWait); + + public long getMinEvictableIdleTimeMillis(); + public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis); + + public int getMinIdle(); + public void setMinIdle(int minIdle); + + public int getNumTestsPerEvictionRun(); + public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun); + + public long getSoftMinEvictableIdleTimeMillis(); + public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis); + + public boolean isTestOnBorrow(); + public void setTestOnBorrow(boolean testOnBorrow); + + public boolean isTestOnReturn(); + public void setTestOnReturn(boolean testOnReturn); + + public boolean isTestWhileIdle(); + public void setTestWhileIdle(boolean testWhileIdle); + + public long getTimeBetweenEvictionRunsMillis(); + public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis); + + public byte getWhenExhaustedAction(); + public void setWhenExhaustedAction(byte whenExhaustedAction); +} diff --git a/src/main/java/org/productivity/java/syslog4j/SyslogRuntimeException.java b/src/main/java/org/productivity/java/syslog4j/SyslogRuntimeException.java new file mode 100644 index 0000000..2c4f311 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/SyslogRuntimeException.java @@ -0,0 +1,24 @@ +package org.productivity.java.syslog4j; + +/** +* SyslogRuntimeException provides an extension of RuntimeException thrown +* by the majority of the classes within Syslog4j. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogRuntimeException.java,v 1.3 2008/11/13 14:48:36 cvs Exp $ +*/ +public class SyslogRuntimeException extends RuntimeException { + private static final long serialVersionUID = 7278123987654320379L; + + public SyslogRuntimeException(String arg0) { + super(arg0); + } + + public SyslogRuntimeException(Throwable arg0) { + super(arg0); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslog.java b/src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslog.java new file mode 100644 index 0000000..86ed89c --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslog.java @@ -0,0 +1,394 @@ +package org.productivity.java.syslog4j.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.productivity.java.syslog4j.SyslogBackLogHandlerIF; +import org.productivity.java.syslog4j.SyslogConfigIF; +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogMessageIF; +import org.productivity.java.syslog4j.SyslogMessageModifierIF; +import org.productivity.java.syslog4j.SyslogMessageProcessorIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.message.processor.SyslogMessageProcessor; +import org.productivity.java.syslog4j.impl.message.processor.structured.StructuredSyslogMessageProcessor; +import org.productivity.java.syslog4j.impl.message.structured.StructuredSyslogMessage; +import org.productivity.java.syslog4j.impl.message.structured.StructuredSyslogMessageIF; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* AbstractSyslog provides a base abstract implementation of the SyslogIF. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractSyslog.java,v 1.29 2011/01/11 04:58:52 cvs Exp $ +*/ +public abstract class AbstractSyslog implements SyslogIF { + private static final long serialVersionUID = 2632017043774808264L; + + protected String syslogProtocol = null; + + protected AbstractSyslogConfigIF syslogConfig = null; + + protected SyslogMessageProcessorIF syslogMessageProcessor = null; + protected SyslogMessageProcessorIF structuredSyslogMessageProcessor = null; + + protected Object backLogStatusSyncObject = new Object(); + + protected boolean backLogStatus = false; + protected List notifiedBackLogHandlers = new ArrayList(); + + protected boolean getBackLogStatus() { + synchronized(this.backLogStatusSyncObject) { + return this.backLogStatus; + } + } + + /** + * @param backLogStatus - true if in a "down" backLog state, false if in an "up" (operational) non-backLog state + */ + public void setBackLogStatus(boolean backLogStatus) { + if (this.backLogStatus != backLogStatus) { + synchronized(this.backLogStatusSyncObject) { + if (!backLogStatus) { + for(int i=0; i 0 && mLength > availableLen) { + mLength = availableLen; + } + } + + if (mLength <= availableLen) { + byte[] data = messageProcessor.createPacketData(h,m,0,mLength); + + write(level,data); + + } else { + byte[] splitBeginText = this.syslogConfig.getSplitMessageBeginText(); + byte[] splitEndText = this.syslogConfig.getSplitMessageEndText(); + + int pos = 0; + int left = mLength; + + while(left > 0) { + boolean firstTime = (pos == 0); + + boolean doSplitBeginText = splitBeginText != null && !firstTime; + boolean doSplitEndText = splitBeginText != null && (firstTime || (left > (availableLen - splitBeginText.length))); + + int actualAvailableLen = availableLen; + + actualAvailableLen -= (splitBeginText != null && doSplitBeginText) ? splitBeginText.length : 0; + actualAvailableLen -= (splitEndText != null && doSplitEndText) ? splitEndText.length : 0; + + if (actualAvailableLen > left) { + actualAvailableLen = left; + } + + if (actualAvailableLen < 0) { + throw new SyslogRuntimeException("Message length < 0; recommendation: increase the size of maxMessageLength"); + } + + byte[] data = messageProcessor.createPacketData(h,m,pos,actualAvailableLen,doSplitBeginText ? splitBeginText : null,doSplitEndText ? splitEndText : null); + + write(level,data); + + pos += actualAvailableLen; + left -= actualAvailableLen; + } + } + } + + protected abstract void initialize() throws SyslogRuntimeException; + + protected abstract void write(int level, byte[] message) throws SyslogRuntimeException; + + protected String modifyMessage(int level, String message) { + List _messageModifiers = this.syslogConfig.getMessageModifiers(); + + if (_messageModifiers == null || _messageModifiers.size() < 1) { + return message; + } + + String _message = message; + + int facility = this.syslogConfig.getFacility(); + + for(int i=0; i<_messageModifiers.size(); i++) { + SyslogMessageModifierIF messageModifier = (SyslogMessageModifierIF) _messageModifiers.get(i); + + _message = messageModifier.modify(this, facility, level, _message); + } + + return _message; + } + + public void backLog(int level, String message, Throwable reasonThrowable) { + backLog(level,message,reasonThrowable != null ? reasonThrowable.toString() : "UNKNOWN"); + } + + public void backLog(int level, String message, String reason) { + boolean status = getBackLogStatus(); + + if (!status) { + setBackLogStatus(true); + } + + List backLogHandlers = this.syslogConfig.getBackLogHandlers(); + + for(int i=0; i -1) { + newWriterThread.setPriority(syslogConfig.getThreadPriority()); + } + syslogWriter.setThread(newWriterThread); + newWriterThread.start(); + + return newWriterThread; + } + + + public AbstractSyslogWriter createWriter(){ + Class clazz = this.syslogConfig.getSyslogWriterClass(); + + AbstractSyslogWriter newWriter = null; + + try { + newWriter = (AbstractSyslogWriter) clazz.newInstance(); + newWriter.initialize(this); + + } catch (InstantiationException ie) { + if (this.syslogConfig.isThrowExceptionOnInitialize()) { + throw new SyslogRuntimeException(ie); + } + + } catch (IllegalAccessException iae) { + if (this.syslogConfig.isThrowExceptionOnInitialize()) { + throw new SyslogRuntimeException(iae); + } + } + + return newWriter; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslogConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslogConfig.java new file mode 100644 index 0000000..ff602f7 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslogConfig.java @@ -0,0 +1,378 @@ +package org.productivity.java.syslog4j.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.productivity.java.syslog4j.SyslogBackLogHandlerIF; +import org.productivity.java.syslog4j.SyslogMessageModifierIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.backlog.printstream.SystemErrSyslogBackLogHandler; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* AbstractSyslog provides a base abstract implementation of the SyslogConfigIF +* configuration interface. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractSyslogConfig.java,v 1.24 2010/11/28 04:43:31 cvs Exp $ +*/ +public abstract class AbstractSyslogConfig implements AbstractSyslogConfigIF { + private static final long serialVersionUID = -3728308557871358111L; + + protected final static List defaultBackLogHandlers = new ArrayList(); + + static { + defaultBackLogHandlers.add(new SystemErrSyslogBackLogHandler()); + } + + protected int facility = SYSLOG_FACILITY_DEFAULT; + + protected String charSet = CHAR_SET_DEFAULT; + + protected String ident = ""; + + protected String localName = null; + + protected boolean sendLocalTimestamp = SEND_LOCAL_TIMESTAMP_DEFAULT; + protected boolean sendLocalName = SEND_LOCAL_NAME_DEFAULT; + + protected boolean includeIdentInMessageModifier = INCLUDE_IDENT_IN_MESSAGE_MODIFIER_DEFAULT; + protected boolean throwExceptionOnWrite = THROW_EXCEPTION_ON_WRITE_DEFAULT; + protected boolean throwExceptionOnInitialize = THROW_EXCEPTION_ON_INITIALIZE_DEFAULT; + + protected int maxMessageLength = MAX_MESSAGE_LENGTH_DEFAULT; + protected byte[] splitMessageBeginText = SPLIT_MESSAGE_BEGIN_TEXT_DEFAULT.getBytes(); + protected byte[] splitMessageEndText = SPLIT_MESSAGE_END_TEXT_DEFAULT.getBytes(); + + protected List messageModifiers = null; + protected List backLogHandlers = null; + + protected boolean threaded = THREADED_DEFAULT; + protected boolean useDaemonThread = USE_DAEMON_THREAD_DEFAULT; + protected int threadPriority = THREAD_PRIORITY_DEFAULT; + protected long threadLoopInterval = THREAD_LOOP_INTERVAL_DEFAULT; + + protected int writeRetries = WRITE_RETRIES_DEFAULT; + protected long maxShutdownWait = MAX_SHUTDOWN_WAIT_DEFAULT; + + protected boolean truncateMessage = TRUNCATE_MESSAGE_DEFAULT; + protected boolean useStructuredData = USE_STRUCTURED_DATA_DEFAULT; + + public abstract Class getSyslogClass(); + + public String getCharSet() { + return this.charSet; + } + + public void setCharSet(String charSet) { + this.charSet = charSet; + } + + public String getLocalName() { + return localName; + } + + public void setLocalName(String localName) { + this.localName = localName; + } + + public boolean isThrowExceptionOnWrite() { + return this.throwExceptionOnWrite; + } + + public void setThrowExceptionOnWrite(boolean throwExceptionOnWrite) { + this.throwExceptionOnWrite = throwExceptionOnWrite; + } + + public boolean isThrowExceptionOnInitialize() { + return this.throwExceptionOnInitialize; + } + + public void setThrowExceptionOnInitialize(boolean throwExceptionOnInitialize) { + this.throwExceptionOnInitialize = throwExceptionOnInitialize; + } + + public byte[] getSplitMessageBeginText() { + return this.splitMessageBeginText; + } + + public void setSplitMessageBeginText(byte[] splitMessageBeginText) { + this.splitMessageBeginText = splitMessageBeginText; + } + + public void setSplitMessageBeginText(String splitMessageBeginText) throws SyslogRuntimeException { + this.splitMessageBeginText = SyslogUtility.getBytes(this,splitMessageBeginText); + } + + public byte[] getSplitMessageEndText() { + return this.splitMessageEndText; + } + + public void setSplitMessageEndText(byte[] splitMessageEndText) { + this.splitMessageEndText = splitMessageEndText; + } + + public void setSplitMessageEndText(String splitMessageEndText) throws SyslogRuntimeException { + this.splitMessageEndText = SyslogUtility.getBytes(this,splitMessageEndText); + } + + public int getMaxMessageLength() { + return this.maxMessageLength; + } + + public void setMaxMessageLength(int maxMessageLength) { + this.maxMessageLength = maxMessageLength; + } + + public boolean isSendLocalTimestamp() { + return this.sendLocalTimestamp; + } + + public void setSendLocalTimestamp(boolean sendLocalTimestamp) { + this.sendLocalTimestamp = sendLocalTimestamp; + } + + public boolean isSendLocalName() { + return this.sendLocalName; + } + + public void setSendLocalName(boolean sendLocalName) { + this.sendLocalName = sendLocalName; + } + + public int getFacility() { + return this.facility; + } + + public void setFacility(int facility) { + this.facility = facility; + } + + public void setFacility(String facilityName) { + this.facility = SyslogUtility.getFacility(facilityName); + } + + public String getIdent() { + return this.ident; + } + + public void setIdent(String ident) { + this.ident = ident; + } + + protected synchronized List _getMessageModifiers() { + if (this.messageModifiers == null) { + this.messageModifiers = new ArrayList(); + } + + return this.messageModifiers; + } + + public void addMessageModifier(SyslogMessageModifierIF messageModifier) { + if (messageModifier == null) { + return; + } + + List _messageModifiers = _getMessageModifiers(); + + synchronized(_messageModifiers) { + _messageModifiers.add(messageModifier); + } + } + + public void insertMessageModifier(int index, SyslogMessageModifierIF messageModifier) { + if (messageModifier == null) { + return; + } + + List _messageModifiers = _getMessageModifiers(); + + synchronized(_messageModifiers) { + try { + _messageModifiers.add(index,messageModifier); + + } catch (IndexOutOfBoundsException ioobe) { + throw new SyslogRuntimeException(ioobe); + } + } + } + + public void removeMessageModifier(SyslogMessageModifierIF messageModifier) { + if (messageModifier == null) { + return; + } + + List _messageModifiers = _getMessageModifiers(); + + synchronized(_messageModifiers) { + _messageModifiers.remove(messageModifier); + } + } + + public List getMessageModifiers() { + return this.messageModifiers; + } + + public void setMessageModifiers(List messageModifiers) { + this.messageModifiers = messageModifiers; + } + + public void removeAllMessageModifiers() { + if (this.messageModifiers == null || this.messageModifiers.isEmpty()) { + return; + } + + this.messageModifiers.clear(); + } + + protected synchronized List _getBackLogHandlers() { + if (this.backLogHandlers == null) { + this.backLogHandlers = new ArrayList(); + } + + return this.backLogHandlers; + } + + public void addBackLogHandler(SyslogBackLogHandlerIF backLogHandler) { + if (backLogHandler == null) { + return; + } + + List _backLogHandlers = _getBackLogHandlers(); + + synchronized(_backLogHandlers) { + backLogHandler.initialize(); + _backLogHandlers.add(backLogHandler); + } + } + + public void insertBackLogHandler(int index, SyslogBackLogHandlerIF backLogHandler) { + if (backLogHandler == null) { + return; + } + + List _backLogHandlers = _getBackLogHandlers(); + + synchronized(_backLogHandlers) { + try { + backLogHandler.initialize(); + _backLogHandlers.add(index,backLogHandler); + + } catch (IndexOutOfBoundsException ioobe) { + throw new SyslogRuntimeException(ioobe); + } + } + } + + public void removeBackLogHandler(SyslogBackLogHandlerIF backLogHandler) { + if (backLogHandler == null) { + return; + } + + List _backLogHandlers = _getBackLogHandlers(); + + synchronized(_backLogHandlers) { + _backLogHandlers.remove(backLogHandler); + } + } + + public List getBackLogHandlers() { + if (this.backLogHandlers == null || this.backLogHandlers.size() < 1) { + return defaultBackLogHandlers; + } + + return this.backLogHandlers; + } + + public void setBackLogHandlers(List backLogHandlers) { + this.backLogHandlers = backLogHandlers; + } + + public void removeAllBackLogHandlers() { + if (this.backLogHandlers == null || this.backLogHandlers.isEmpty()) { + return; + } + + this.backLogHandlers.clear(); + } + + public boolean isIncludeIdentInMessageModifier() { + return this.includeIdentInMessageModifier; + } + + public void setIncludeIdentInMessageModifier(boolean includeIdentInMessageModifier) { + this.includeIdentInMessageModifier = includeIdentInMessageModifier; + } + + public boolean isThreaded() { + return this.threaded; + } + + public void setThreaded(boolean threaded) { + this.threaded = threaded; + } + + public boolean isUseDaemonThread() { + return useDaemonThread; + } + + public void setUseDaemonThread(boolean useDaemonThread) { + this.useDaemonThread = useDaemonThread; + } + + public int getThreadPriority() { + return threadPriority; + } + + public void setThreadPriority(int threadPriority) { + this.threadPriority = threadPriority; + } + + public long getThreadLoopInterval() { + return this.threadLoopInterval; + } + + public void setThreadLoopInterval(long threadLoopInterval) { + this.threadLoopInterval = threadLoopInterval; + } + + public long getMaxShutdownWait() { + return this.maxShutdownWait; + } + + public void setMaxShutdownWait(long maxShutdownWait) { + this.maxShutdownWait = maxShutdownWait; + } + + public int getWriteRetries() { + return this.writeRetries; + } + + public void setWriteRetries(int writeRetries) { + this.writeRetries = writeRetries; + } + + public boolean isTruncateMessage() { + return this.truncateMessage; + } + + public void setTruncateMessage(boolean truncateMessage) { + this.truncateMessage = truncateMessage; + } + + public boolean isUseStructuredData() { + return this.useStructuredData; + } + + public void setUseStructuredData(boolean useStructuredData) { + this.useStructuredData = useStructuredData; + } + + public Class getSyslogWriterClass() { + return null; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslogConfigIF.java b/src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslogConfigIF.java new file mode 100644 index 0000000..cc3ed03 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslogConfigIF.java @@ -0,0 +1,56 @@ +package org.productivity.java.syslog4j.impl; + +import java.util.List; + +import org.productivity.java.syslog4j.SyslogConfigIF; + +/** +* AbstractSyslogConfigIF provides an interface for all Abstract Syslog +* configuration implementations. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractSyslogConfigIF.java,v 1.7 2010/10/29 03:14:20 cvs Exp $ +*/ +public interface AbstractSyslogConfigIF extends SyslogConfigIF { + public Class getSyslogWriterClass(); + + public List getBackLogHandlers(); + + public List getMessageModifiers(); + + public byte[] getSplitMessageBeginText(); + public void setSplitMessageBeginText(byte[] beginText); + + public byte[] getSplitMessageEndText(); + public void setSplitMessageEndText(byte[] endText); + + public boolean isThreaded(); + public void setThreaded(boolean threaded); + + public boolean isUseDaemonThread(); + public void setUseDaemonThread(boolean useDaemonThread); + + public int getThreadPriority(); + public void setThreadPriority(int threadPriority); + + public long getThreadLoopInterval(); + public void setThreadLoopInterval(long threadLoopInterval); + + public long getMaxShutdownWait(); + public void setMaxShutdownWait(long maxShutdownWait); + + public int getWriteRetries(); + public void setWriteRetries(int writeRetries); + + public int getMaxQueueSize(); + /** + * Use the (default) value of -1 to allow for a queue of indefinite depth (size). + * + * @param maxQueueSize + */ + public void setMaxQueueSize(int maxQueueSize); +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslogWriter.java b/src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslogWriter.java new file mode 100644 index 0000000..5386105 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/AbstractSyslogWriter.java @@ -0,0 +1,109 @@ +package org.productivity.java.syslog4j.impl; + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* AbstractSyslogWriter is an implementation of Runnable that supports sending +* syslog messages within a separate Thread or an object pool. +* +*

When used in "threaded" mode (see TCPNetSyslogConfig for the option), +* a queuing mechanism is used (via LinkedList).

+* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractSyslogWriter.java,v 1.9 2010/10/25 03:50:25 cvs Exp $ +*/ +public abstract class AbstractSyslogWriter implements Runnable, Serializable { + private static final long serialVersionUID = 836468466009035847L; + + protected AbstractSyslog syslog = null; + + protected List queuedMessages = null; + + protected Thread thread = null; + + protected AbstractSyslogConfigIF syslogConfig = null; + + protected boolean shutdown = false; + + public void initialize(AbstractSyslog abstractSyslog) { + this.syslog = abstractSyslog; + + try { + this.syslogConfig = (AbstractSyslogConfigIF) this.syslog.getConfig(); + + } catch (ClassCastException cce) { + throw new SyslogRuntimeException("config must implement interface AbstractSyslogConfigIF"); + } + + if (this.syslogConfig.isThreaded()) { + this.queuedMessages = new LinkedList(); + } + } + + public void queue(int level, byte[] message) { + synchronized(this.queuedMessages) { + if (this.syslogConfig.getMaxQueueSize() == -1 || this.queuedMessages.size() < this.syslogConfig.getMaxQueueSize()) { + this.queuedMessages.add(message); + + } else { + this.syslog.backLog(level,SyslogUtility.newString(syslogConfig,message),"MaxQueueSize (" + this.syslogConfig.getMaxQueueSize() + ") reached"); + } + } + } + + public void setThread(Thread thread) { + this.thread = thread; + } + + public boolean hasThread() { + return this.thread != null && this.thread.isAlive(); + } + + public abstract void write(byte[] message); + + public abstract void flush(); + + public abstract void shutdown(); + + protected abstract void runCompleted(); + + public void run() { + while(!this.shutdown || !this.queuedMessages.isEmpty()) { + List queuedMessagesCopy = null; + + synchronized(this.queuedMessages) { + queuedMessagesCopy = new LinkedList(this.queuedMessages); + this.queuedMessages.clear(); + } + + if (queuedMessagesCopy != null) { + while(!queuedMessagesCopy.isEmpty()) { + byte[] message = (byte[]) queuedMessagesCopy.remove(0); + + try { + write(message); + + this.syslog.setBackLogStatus(false); + + } catch (SyslogRuntimeException sre) { + this.syslog.backLog(SyslogConstants.LEVEL_INFO,SyslogUtility.newString(this.syslog.getConfig(),message),sre); + } + } + } + + SyslogUtility.sleep(this.syslogConfig.getThreadLoopInterval()); + } + + runCompleted(); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/backlog/AbstractSyslogBackLogHandler.java b/src/main/java/org/productivity/java/syslog4j/impl/backlog/AbstractSyslogBackLogHandler.java new file mode 100644 index 0000000..09dd6a6 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/backlog/AbstractSyslogBackLogHandler.java @@ -0,0 +1,36 @@ +package org.productivity.java.syslog4j.impl.backlog; + +import org.productivity.java.syslog4j.SyslogBackLogHandlerIF; +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* AbstractSyslogBackLogHandler is an implementation of SyslogBackLogHandlerIF +* that mainly provides the helpful "combine" method for handling the "reason" +* why a BackLog has occurred. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractSyslogBackLogHandler.java,v 1.1 2009/01/24 22:00:18 cvs Exp $ +*/ +public abstract class AbstractSyslogBackLogHandler implements SyslogBackLogHandlerIF { + protected boolean appendReason = true; + + protected String combine(SyslogIF syslog, int level, String message, String reason) { + // Note: syslog is explicitly ignored by default + + String _message = message != null ? message : "UNKNOWN"; + String _reason = reason != null ? reason : "UNKNOWN"; + + String combinedMessage = SyslogUtility.getLevelString(level) + " " + _message; + + if (this.appendReason) { + combinedMessage += " [" + _reason + "]"; + } + + return combinedMessage; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/backlog/NullSyslogBackLogHandler.java b/src/main/java/org/productivity/java/syslog4j/impl/backlog/NullSyslogBackLogHandler.java new file mode 100644 index 0000000..74ddab2 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/backlog/NullSyslogBackLogHandler.java @@ -0,0 +1,35 @@ +package org.productivity.java.syslog4j.impl.backlog; + +import org.productivity.java.syslog4j.SyslogBackLogHandlerIF; +import org.productivity.java.syslog4j.SyslogIF; + +/** +* NullSyslogBackLogHandler can be used if there's no need for a last-chance +* logging mechanism whenever the Syslog protocol fails. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: NullSyslogBackLogHandler.java,v 1.2 2010/10/25 03:50:25 cvs Exp $ +*/ +public class NullSyslogBackLogHandler implements SyslogBackLogHandlerIF { + public static final NullSyslogBackLogHandler INSTANCE = new NullSyslogBackLogHandler(); + + public void initialize() { + // + } + + public void down(SyslogIF syslog, String reason) { + // + } + + public void up(SyslogIF syslog) { + // + } + + public void log(SyslogIF syslog, int level, String message, String reason) { + // + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/backlog/Syslog4jBackLogHandler.java b/src/main/java/org/productivity/java/syslog4j/impl/backlog/Syslog4jBackLogHandler.java new file mode 100644 index 0000000..bf819ec --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/backlog/Syslog4jBackLogHandler.java @@ -0,0 +1,67 @@ +package org.productivity.java.syslog4j.impl.backlog; + +import org.productivity.java.syslog4j.Syslog; +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; + +/** +* Syslog4jBackLogHandler is used to send Syslog backLog messages to +* another Syslog4j protocol whenever the main Syslog protocol fails. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: Syslog4jBackLogHandler.java,v 1.1 2009/07/25 18:42:47 cvs Exp $ +*/ +public class Syslog4jBackLogHandler extends AbstractSyslogBackLogHandler { + protected SyslogIF syslog = null; + protected int downLevel = SyslogConstants.LEVEL_WARN; + protected int upLevel = SyslogConstants.LEVEL_WARN; + + public Syslog4jBackLogHandler(String protocol) { + this.syslog = Syslog.getInstance(protocol); + } + + public Syslog4jBackLogHandler(String protocol, boolean appendReason) { + this.syslog = Syslog.getInstance(protocol); + this.appendReason = appendReason; + } + + public Syslog4jBackLogHandler(SyslogIF syslog) { + this.syslog = syslog; + } + + public Syslog4jBackLogHandler(SyslogIF syslog, boolean appendReason) { + this.syslog = syslog; + this.appendReason = appendReason; + } + + public void initialize() throws SyslogRuntimeException { + // NO-OP + } + + public void log(SyslogIF syslog, int level, String message, String reason) throws SyslogRuntimeException { + if (this.syslog.getProtocol().equals(syslog.getProtocol())) { + throw new SyslogRuntimeException("Ignoring this log entry since the backLog protocol \"" + this.syslog.getProtocol() + "\" is the same as the main protocol"); + } + + String combinedMessage = combine(syslog,level,message,reason); + + this.syslog.log(level,combinedMessage); + } + + public void down(SyslogIF syslog, String reason) { + if (!this.syslog.getProtocol().equals(syslog.getProtocol())) { + this.syslog.log(this.downLevel,"Syslog protocol \"" + syslog.getProtocol() + "\" is down: " + reason); + } + } + + public void up(SyslogIF syslog) { + if (!this.syslog.getProtocol().equals(syslog.getProtocol())) { + this.syslog.log(this.downLevel,"Syslog protocol \"" + syslog.getProtocol() + "\" is up"); + } + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/backlog/log4j/Log4jSyslogBackLogHandler.java b/src/main/java/org/productivity/java/syslog4j/impl/backlog/log4j/Log4jSyslogBackLogHandler.java new file mode 100644 index 0000000..b05cecc --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/backlog/log4j/Log4jSyslogBackLogHandler.java @@ -0,0 +1,148 @@ +package org.productivity.java.syslog4j.impl.backlog.log4j; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.log4j.spi.LoggerFactory; +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.backlog.AbstractSyslogBackLogHandler; + +/** +* Log4jSyslogBackLogHandler is used to send Syslog backLog messages to +* Log4j whenever the Syslog protocol fails. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: Log4jSyslogBackLogHandler.java,v 1.2 2009/07/22 15:54:23 cvs Exp $ +*/ +public class Log4jSyslogBackLogHandler extends AbstractSyslogBackLogHandler { + protected Logger logger = null; + protected Level downLevel = Level.WARN; + protected Level upLevel = Level.WARN; + + public Log4jSyslogBackLogHandler(Logger logger) throws SyslogRuntimeException { + this.logger = logger; + + initialize(); + } + + public Log4jSyslogBackLogHandler(Logger logger, boolean appendReason) { + this.logger = logger; + this.appendReason = appendReason; + + initialize(); + } + + public Log4jSyslogBackLogHandler(Class loggerClass) { + if (loggerClass == null) { + throw new SyslogRuntimeException("loggerClass cannot be null"); + } + + this.logger = Logger.getLogger(loggerClass); + + initialize(); + } + + public Log4jSyslogBackLogHandler(Class loggerClass, boolean appendReason) { + if (loggerClass == null) { + throw new SyslogRuntimeException("loggerClass cannot be null"); + } + + this.logger = Logger.getLogger(loggerClass); + this.appendReason = appendReason; + + initialize(); + } + + public Log4jSyslogBackLogHandler(String loggerName) { + if (loggerName == null) { + throw new SyslogRuntimeException("loggerName cannot be null"); + } + + this.logger = Logger.getLogger(loggerName); + + initialize(); + } + + public Log4jSyslogBackLogHandler(String loggerName, boolean appendReason) { + if (loggerName == null) { + throw new SyslogRuntimeException("loggerName cannot be null"); + } + + this.logger = Logger.getLogger(loggerName); + this.appendReason = appendReason; + + initialize(); + } + + public Log4jSyslogBackLogHandler(String loggerName, LoggerFactory loggerFactory) { + if (loggerName == null) { + throw new SyslogRuntimeException("loggerName cannot be null"); + } + + if (loggerFactory == null) { + throw new SyslogRuntimeException("loggerFactory cannot be null"); + } + + this.logger = Logger.getLogger(loggerName,loggerFactory); + + initialize(); + } + + public Log4jSyslogBackLogHandler(String loggerName, LoggerFactory loggerFactory, boolean appendReason) { + if (loggerName == null) { + throw new SyslogRuntimeException("loggerName cannot be null"); + } + + if (loggerFactory == null) { + throw new SyslogRuntimeException("loggerFactory cannot be null"); + } + + this.logger = Logger.getLogger(loggerName,loggerFactory); + this.appendReason = appendReason; + + initialize(); + } + + public void initialize() throws SyslogRuntimeException { + if (this.logger == null) { + throw new SyslogRuntimeException("logger cannot be null"); + } + } + + protected static Level getLog4jLevel(int level) { + switch(level) { + case SyslogConstants.LEVEL_DEBUG: return Level.DEBUG; + case SyslogConstants.LEVEL_INFO: return Level.INFO; + case SyslogConstants.LEVEL_NOTICE: return Level.INFO; + case SyslogConstants.LEVEL_WARN: return Level.WARN; + case SyslogConstants.LEVEL_ERROR: return Level.ERROR; + case SyslogConstants.LEVEL_CRITICAL: return Level.ERROR; + case SyslogConstants.LEVEL_ALERT: return Level.ERROR; + case SyslogConstants.LEVEL_EMERGENCY: return Level.FATAL; + + default: + return Level.WARN; + } + } + + public void down(SyslogIF syslog, String reason) { + this.logger.log(this.downLevel,"Syslog protocol \"" + syslog.getProtocol() + "\" is down: " + reason); + } + + public void up(SyslogIF syslog) { + this.logger.log(this.upLevel,"Syslog protocol \"" + syslog.getProtocol() + "\" is up"); + } + + public void log(SyslogIF syslog, int level, String message, String reason) throws SyslogRuntimeException { + Level log4jLevel = getLog4jLevel(level); + + String combinedMessage = combine(syslog,level,message,reason); + + this.logger.log(log4jLevel,combinedMessage); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/backlog/printstream/PrintStreamSyslogBackLogHandler.java b/src/main/java/org/productivity/java/syslog4j/impl/backlog/printstream/PrintStreamSyslogBackLogHandler.java new file mode 100644 index 0000000..d9fc80c --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/backlog/printstream/PrintStreamSyslogBackLogHandler.java @@ -0,0 +1,69 @@ +package org.productivity.java.syslog4j.impl.backlog.printstream; + +import java.io.PrintStream; + +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.backlog.AbstractSyslogBackLogHandler; + +/** +* PrintStreamSyslogBackLogHandler provides a last-chance mechanism to log messages that fail +* (for whatever reason) within the rest of Syslog to a PrintStream. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: PrintStreamSyslogBackLogHandler.java,v 1.1 2009/01/24 22:00:18 cvs Exp $ +*/ +public class PrintStreamSyslogBackLogHandler extends AbstractSyslogBackLogHandler { + protected PrintStream printStream = null; + protected boolean appendLinefeed = false; + + public PrintStreamSyslogBackLogHandler(PrintStream printStream) { + this.printStream = printStream; + + initialize(); + } + + public PrintStreamSyslogBackLogHandler(PrintStream printStream, boolean appendLinefeed) { + this.printStream = printStream; + this.appendLinefeed = appendLinefeed; + + initialize(); + } + + public PrintStreamSyslogBackLogHandler(PrintStream printStream, boolean appendLinefeed, boolean appendReason) { + this.printStream = printStream; + this.appendLinefeed = appendLinefeed; + this.appendReason = appendReason; + + initialize(); + } + + public void initialize() throws SyslogRuntimeException { + if (this.printStream == null) { + throw new SyslogRuntimeException("PrintStream cannot be null"); + } + } + + public void down(SyslogIF syslog, String reason) { + this.printStream.println(syslog.getProtocol() + ": DOWN" + (reason != null && !"".equals(reason.trim()) ? " (" + reason + ")" : "")); + } + + public void up(SyslogIF syslog) { + this.printStream.println(syslog.getProtocol() + ": UP"); + } + + public void log(SyslogIF syslog, int level, String message, String reason) { + String combinedMessage = combine(syslog,level,message,reason); + + if (this.appendLinefeed) { + this.printStream.println(combinedMessage); + + } else { + this.printStream.print(combinedMessage); + } + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/backlog/printstream/SystemErrSyslogBackLogHandler.java b/src/main/java/org/productivity/java/syslog4j/impl/backlog/printstream/SystemErrSyslogBackLogHandler.java new file mode 100644 index 0000000..814e5eb --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/backlog/printstream/SystemErrSyslogBackLogHandler.java @@ -0,0 +1,27 @@ +package org.productivity.java.syslog4j.impl.backlog.printstream; + +import org.productivity.java.syslog4j.SyslogBackLogHandlerIF; + +/** +* SystemErrSyslogBackLogHandler provides a last-chance mechanism to log messages that fail +* (for whatever reason) within the rest of Syslog to System.err. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SystemErrSyslogBackLogHandler.java,v 1.2 2009/03/29 17:38:59 cvs Exp $ +*/ +public class SystemErrSyslogBackLogHandler extends PrintStreamSyslogBackLogHandler { + public static final SyslogBackLogHandlerIF create() { + return new SystemErrSyslogBackLogHandler(); + } + + public SystemErrSyslogBackLogHandler() { + super(System.err,true); + } + public SystemErrSyslogBackLogHandler(boolean appendReason) { + super(System.err,true,appendReason); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/backlog/printstream/SystemOutSyslogBackLogHandler.java b/src/main/java/org/productivity/java/syslog4j/impl/backlog/printstream/SystemOutSyslogBackLogHandler.java new file mode 100644 index 0000000..48e0062 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/backlog/printstream/SystemOutSyslogBackLogHandler.java @@ -0,0 +1,27 @@ +package org.productivity.java.syslog4j.impl.backlog.printstream; + +import org.productivity.java.syslog4j.SyslogBackLogHandlerIF; + +/** +* SystemOutSyslogBackLogHandler provides a last-chance mechanism to log messages that fail +* (for whatever reason) within the rest of Syslog to System.out. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SystemOutSyslogBackLogHandler.java,v 1.2 2009/03/29 17:38:59 cvs Exp $ +*/ +public class SystemOutSyslogBackLogHandler extends PrintStreamSyslogBackLogHandler { + public static final SyslogBackLogHandlerIF create() { + return new SystemOutSyslogBackLogHandler(); + } + + public SystemOutSyslogBackLogHandler() { + super(System.out,true); + } + public SystemOutSyslogBackLogHandler(boolean appendReason) { + super(System.out,true,appendReason); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/log4j/Syslog4jAppender.java b/src/main/java/org/productivity/java/syslog4j/impl/log4j/Syslog4jAppender.java new file mode 100644 index 0000000..604530b --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/log4j/Syslog4jAppender.java @@ -0,0 +1,79 @@ +package org.productivity.java.syslog4j.impl.log4j; + +import org.apache.log4j.helpers.LogLog; + +/** + * Syslog4jAppender provides a Log4j Appender wrapper for Syslog4j. + * + *

Note: Syslog4jAppender does NOT extend Log4j's SyslogAppender.

+ * + *

Example log4j.xml configuration:

+ * + *
+ * 
+   <appender name="Syslog4j" class="org.productivity.java.syslog4j.impl.log4j.Syslog4jAppender">
+		<param name="Facility" value="user"/>
+		<param name="Protocol" value="tcp"/>
+		<param name="Host" value="192.168.0.1"/>
+		<layout class="org.apache.log4j.PatternLayout">
+			<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m"/>
+		</layout>
+   </appender>
+ * 
+ * 
+ * + *

All available parameters are:

+ * + *
    + *
  • ident
  • + *
  • localName
  • + *
  • protocol
  • + *
  • facility
  • + *
  • host
  • + *
  • port
  • + *
  • charSet
  • + *
  • threaded
  • + *
  • threadLoopInterval
  • + *
  • splitMessageBeginText
  • + *
  • splitMessageEndText
  • + *
  • maxMessageLength
  • + *
  • maxShutdownWait
  • + *
  • writeRetries
  • + *
  • truncateMessage
  • + *
  • useStructuredData
  • + *
+ * + *

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy + * of the LGPL license is available in the META-INF folder in all + * distributions of Syslog4j and in the base directory of the "doc" ZIP.

+ * + * @author <syslog4j@productivity.org> + * @version $Id: Syslog4jAppender.java,v 1.2 2011/01/23 20:49:12 cvs Exp $ + */ +public class Syslog4jAppender extends Syslog4jAppenderSkeleton { + private static final long serialVersionUID = -6072552977605816670L; + + public String initialize() { + if (this.protocol == null) { + this.protocol = UDP; + } + + return this.protocol; + } + + public boolean getHeader() { + return false; + } + + public void setHeader(boolean header) { + LogLog.warn("Syslog4jAppender ignores the \"Header\" parameter."); + } + + public String getSyslogHost() { + return this.host; + } + + public void setSyslogHost(String host) { + this.host = host; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/log4j/Syslog4jAppenderSkeleton.java b/src/main/java/org/productivity/java/syslog4j/impl/log4j/Syslog4jAppenderSkeleton.java new file mode 100644 index 0000000..cc7f7e7 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/log4j/Syslog4jAppenderSkeleton.java @@ -0,0 +1,331 @@ +package org.productivity.java.syslog4j.impl.log4j; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.helpers.LogLog; +import org.apache.log4j.spi.LoggingEvent; +import org.productivity.java.syslog4j.Syslog; +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.AbstractSyslogConfigIF; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** + * Syslog4jAppenderSkeleton provides an extensible Log4j Appender wrapper for Syslog4j. + * + *

Classes which inherit Syslog4jAppenderSkeleton must implement the "initialize()" method, + * which sets up Syslog4j for use by the Log4j Appender.

+ * + *

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy + * of the LGPL license is available in the META-INF folder in all + * distributions of Syslog4j and in the base directory of the "doc" ZIP.

+ * + * @author <syslog4j@productivity.org> + * @version $Id: Syslog4jAppenderSkeleton.java,v 1.8 2011/01/23 20:49:12 cvs Exp $ + */ +public abstract class Syslog4jAppenderSkeleton extends AppenderSkeleton implements SyslogConstants { + private static final long serialVersionUID = 5520555788232095628L; + + protected SyslogIF syslog = null; + + protected String ident = null; + protected String localName = null; + protected String protocol = null; + protected String facility = null; + protected String host = null; + protected String port = null; + protected String charSet = null; + protected String threaded = null; + protected String threadLoopInterval = null; + protected String splitMessageBeginText = null; + protected String splitMessageEndText = null; + protected String maxMessageLength = null; + protected String maxShutdownWait = null; + protected String writeRetries = null; + protected String truncateMessage = null; + protected String useStructuredData = null; + + protected boolean initialized = false; + + public abstract String initialize() throws SyslogRuntimeException; + + protected static boolean isTrueOrOn(String value) { + boolean trueOrOn = false; + + if (value != null) { + if ("true".equalsIgnoreCase(value.trim()) || "on".equalsIgnoreCase(value.trim())) { + trueOrOn = true; + + } else if ("false".equalsIgnoreCase(value.trim()) || "off".equalsIgnoreCase(value.trim())) { + trueOrOn = false; + + } else { + LogLog.error("Value \"" + value + "\" not true, on, false, or off -- assuming false"); + } + } + + return trueOrOn; + } + + protected void _initialize() { + String initializedProtocol = initialize(); + + if (initializedProtocol != null && this.protocol == null) { + this.protocol = initializedProtocol; + } + + if (this.protocol != null) { + try { + this.syslog = Syslog.getInstance(this.protocol); + if (this.host != null) { + this.syslog.getConfig().setHost(this.host); + } + if (this.facility != null) { + this.syslog.getConfig().setFacility(SyslogUtility.getFacility(this.facility)); + } + if (this.port != null) { + try { + int i = Integer.parseInt(this.port); + this.syslog.getConfig().setPort(i); + + } catch (NumberFormatException nfe) { + LogLog.error(nfe.toString()); + } + } + if (this.charSet != null) { + this.syslog.getConfig().setCharSet(this.charSet); + } + if (this.ident != null) { + this.syslog.getConfig().setIdent(this.ident); + } + if (this.localName != null) { + this.syslog.getConfig().setLocalName(this.localName); + } + if (this.truncateMessage != null && !"".equals(this.truncateMessage.trim())) { + this.syslog.getConfig().setTruncateMessage(isTrueOrOn(this.truncateMessage)); + } + if (this.maxMessageLength != null && this.maxMessageLength.length() > 0) { + try { + int i = Integer.parseInt(this.maxMessageLength.trim()); + this.syslog.getConfig().setMaxMessageLength(i); + + } catch (NumberFormatException nfe) { + LogLog.error(nfe.toString()); + } + } + if (this.useStructuredData != null) { + this.syslog.getConfig().setUseStructuredData(isTrueOrOn(this.useStructuredData)); + } + if (this.syslog.getConfig() instanceof AbstractSyslogConfigIF) { + AbstractSyslogConfigIF abstractSyslogConfig = (AbstractSyslogConfigIF) this.syslog.getConfig(); + + if (this.threaded != null && !"".equals(this.threaded.trim())) { + abstractSyslogConfig.setThreaded(isTrueOrOn(this.threaded)); + } + + if (this.threadLoopInterval != null && this.threadLoopInterval.length() > 0) { + try { + long l = Long.parseLong(this.threadLoopInterval.trim()); + abstractSyslogConfig.setThreadLoopInterval(l); + + } catch (NumberFormatException nfe) { + LogLog.error(nfe.toString()); + } + } + + if (this.splitMessageBeginText != null) { + abstractSyslogConfig.setSplitMessageBeginText(SyslogUtility.getBytes(abstractSyslogConfig,this.splitMessageBeginText)); + } + + if (this.splitMessageEndText != null) { + abstractSyslogConfig.setSplitMessageEndText(SyslogUtility.getBytes(abstractSyslogConfig,this.splitMessageEndText)); + } + + if (this.maxShutdownWait != null && this.maxShutdownWait.length() > 0) { + try { + int i = Integer.parseInt(this.maxShutdownWait.trim()); + abstractSyslogConfig.setMaxShutdownWait(i); + + } catch (NumberFormatException nfe) { + LogLog.error(nfe.toString()); + } + } + + if (this.writeRetries != null && this.writeRetries.length() > 0) { + try { + int i = Integer.parseInt(this.writeRetries.trim()); + abstractSyslogConfig.setWriteRetries(i); + + } catch (NumberFormatException nfe) { + LogLog.error(nfe.toString()); + } + } + } + + this.initialized = true; + + } catch (SyslogRuntimeException sre) { + LogLog.error(sre.toString()); + } + } + } + + public String getProtocol() { + return this.protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + protected void append(LoggingEvent event) { + if (!this.initialized) { + _initialize(); + } + + if (this.initialized) { + int level = event.getLevel().getSyslogEquivalent(); + + if (this.layout != null) { + String message = this.layout.format(event); + + this.syslog.log(level,message); + + } else { + String message = event.getRenderedMessage(); + + this.syslog.log(level,message); + } + } + } + + public void close() { + if (this.syslog != null) { + this.syslog.flush(); + } + } + + public String getFacility() { + return this.facility; + } + + public void setFacility(String facility) { + this.facility = facility; + } + + public String getHost() { + return this.host; + } + + public void setHost(String host) { + this.host = host; + } + + public String getLocalName() { + return localName; + } + + public void setLocalName(String localName) { + this.localName = localName; + } + + public String getPort() { + return this.port; + } + + public void setPort(String port) { + this.port = port; + } + + public String getCharSet() { + return this.charSet; + } + + public void setCharSet(String charSet) { + this.charSet = charSet; + } + + public String getIdent() { + return this.ident; + } + + public void setIdent(String ident) { + this.ident = ident; + } + + public String getThreaded() { + return this.threaded; + } + + public void setThreaded(String threaded) { + this.threaded = threaded; + } + + public boolean requiresLayout() { + return false; + } + + public String getThreadLoopInterval() { + return this.threadLoopInterval; + } + + public void setThreadLoopInterval(String threadLoopInterval) { + this.threadLoopInterval = threadLoopInterval; + } + + public String getSplitMessageBeginText() { + return this.splitMessageBeginText; + } + + public void setSplitMessageBeginText(String splitMessageBeginText) { + this.splitMessageBeginText = splitMessageBeginText; + } + + public String getSplitMessageEndText() { + return this.splitMessageEndText; + } + + public void setSplitMessageEndText(String splitMessageEndText) { + this.splitMessageEndText = splitMessageEndText; + } + + public String getMaxMessageLength() { + return this.maxMessageLength; + } + + public void setMaxMessageLength(String maxMessageLength) { + this.maxMessageLength = maxMessageLength; + } + + public String getMaxShutdownWait() { + return this.maxShutdownWait; + } + + public void setMaxShutdownWait(String maxShutdownWait) { + this.maxShutdownWait = maxShutdownWait; + } + + public String getWriteRetries() { + return this.writeRetries; + } + + public void setWriteRetries(String writeRetries) { + this.writeRetries = writeRetries; + } + + public String getTruncateMessage() { + return this.truncateMessage; + } + + public void setTruncateMessage(String truncateMessage) { + this.truncateMessage = truncateMessage; + } + + public String getUseStructuredData() { + return useStructuredData; + } + + public void setUseStructuredData(String useStructuredData) { + this.useStructuredData = useStructuredData; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/AbstractSyslogMessage.java b/src/main/java/org/productivity/java/syslog4j/impl/message/AbstractSyslogMessage.java new file mode 100644 index 0000000..f6cee50 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/AbstractSyslogMessage.java @@ -0,0 +1,101 @@ +package org.productivity.java.syslog4j.impl.message; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.productivity.java.syslog4j.SyslogMessageIF; + +/** +* AbstractSyslogMessage provides support for turning POJO (Plain Ol' +* Java Objects) into Syslog messages. +* +*

More information on the PCI DSS specification is available here:

+* +*

https://www.pcisecuritystandards.org/security_standards/pci_dss.shtml

+* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractSyslogMessage.java,v 1.2 2009/04/17 02:37:04 cvs Exp $ +*/ +public abstract class AbstractSyslogMessage implements SyslogMessageIF { + private static final long serialVersionUID = 414124277626756491L; + + public static final String UNDEFINED = "undefined"; + + public static final String DEFAULT_DATE_FORMAT = "yyyy/MM/dd"; + public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss"; + + public static final char DEFAULT_DELIMITER = ' '; + public static final String DEFAULT_REPLACE_DELIMITER = "_"; + + protected char getDelimiter() { + return DEFAULT_DELIMITER; + } + + protected String getReplaceDelimiter() { + return DEFAULT_REPLACE_DELIMITER; + } + + protected String getDateFormat() { + return DEFAULT_DATE_FORMAT; + } + + protected String getTimeFormat() { + return DEFAULT_TIME_FORMAT; + } + + protected String generateDate() { + String date = new SimpleDateFormat(getDateFormat()).format(new Date()); + + return date; + } + + protected String generateTime() { + String time = new SimpleDateFormat(getTimeFormat()).format(new Date()); + + return time; + } + + protected String[] generateDateAndTime(Date date) { + String[] dateAndTime = new String[2]; + + dateAndTime[0] = new SimpleDateFormat(getDateFormat()).format(date); + dateAndTime[1] = new SimpleDateFormat(getTimeFormat()).format(date); + + return dateAndTime; + } + + protected String generateLocalHostName() { + String localHostName = UNDEFINED; + + try { + localHostName = InetAddress.getLocalHost().getHostName(); + + } catch (UnknownHostException uhe) { + // + } + + return localHostName; + } + + protected boolean nullOrEmpty(String value) { + return (value == null || "".equals(value.trim())); + } + + protected String replaceDelimiter(String fieldName, String fieldValue, char delimiter, String replaceDelimiter) { + if (replaceDelimiter == null || replaceDelimiter.length() < 1 || fieldValue == null || fieldValue.length() < 1) { + return fieldValue; + } + + String newFieldValue = fieldValue.replaceAll("\\" + delimiter, replaceDelimiter); + + return newFieldValue; + } + + public abstract String createMessage(); +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifier.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifier.java new file mode 100644 index 0000000..33b586b --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifier.java @@ -0,0 +1,63 @@ +package org.productivity.java.syslog4j.impl.message.modifier; + +import org.productivity.java.syslog4j.SyslogMessageModifierConfigIF; +import org.productivity.java.syslog4j.SyslogMessageModifierIF; + +public abstract class AbstractSyslogMessageModifier implements SyslogMessageModifierIF { + private static final long serialVersionUID = 7632959170109372003L; + + protected SyslogMessageModifierConfigIF messageModifierConfig = null; + + public AbstractSyslogMessageModifier(SyslogMessageModifierConfigIF messageModifierConfig) { + this.messageModifierConfig = messageModifierConfig; + } + + public String[] parseInlineModifier(String message) { + return parseInlineModifier(message,this.messageModifierConfig.getPrefix(),this.messageModifierConfig.getSuffix()); + } + + public static String[] parseInlineModifier(String message, String prefix, String suffix) { + String[] messageAndModifier = null; + + if (message == null || "".equals(message.trim())) { + return null; + } + + if (prefix == null || "".equals(prefix)) { + prefix = " "; + } + + if (suffix == null || "".equals(suffix)) { + int pi = message.lastIndexOf(prefix); + + if (pi > -1) { + messageAndModifier = new String[] { message.substring(0,pi), message.substring(pi+prefix.length()) }; + } + + } else { + int si = message.lastIndexOf(suffix); + + if (si > -1) { + int pi = message.lastIndexOf(prefix,si); + + if (pi > -1) { + messageAndModifier = new String[] { message.substring(0,pi), message.substring(pi+prefix.length(),si) }; + } + } + } + + return messageAndModifier; + } + + protected abstract boolean verify(String message, String modifier); + + public boolean verify(String message) { + String[] messageAndModifier = parseInlineModifier(message); + + if (messageAndModifier == null || messageAndModifier.length != 2) { + return false; + } + + return verify(messageAndModifier[0],messageAndModifier[1]); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifierConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifierConfig.java new file mode 100644 index 0000000..cb97b71 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifierConfig.java @@ -0,0 +1,58 @@ +package org.productivity.java.syslog4j.impl.message.modifier; + +import org.productivity.java.syslog4j.SyslogCharSetIF; +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogMessageModifierConfigIF; + +/** +* AbstractSyslogMessageModifierConfig provides a base abstract implementation of the +* SyslogMessageModifierConfigIF. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractSyslogMessageModifierConfig.java,v 1.4 2010/10/28 05:10:57 cvs Exp $ +*/ +public abstract class AbstractSyslogMessageModifierConfig implements SyslogMessageModifierConfigIF, SyslogCharSetIF { + private static final long serialVersionUID = 5036574188079124884L; + + protected String prefix = SYSLOG_MESSAGE_MODIFIER_PREFIX_DEFAULT; + protected String suffix = SYSLOG_MESSAGE_MODIFIER_SUFFIX_DEFAULT; + protected String charSet = SyslogConstants.CHAR_SET_DEFAULT; + + public String getPrefix() { + return this.prefix; + } + + public String getSuffix() { + return this.suffix; + } + + public void setPrefix(String prefix) { + if (prefix == null) { + this.prefix = ""; + + } else { + this.prefix = prefix; + } + } + + public void setSuffix(String suffix) { + if (suffix == null) { + this.suffix = ""; + + } else { + this.suffix = suffix; + } + } + + public String getCharSet() { + return charSet; + } + + public void setCharSet(String charSet) { + this.charSet = charSet; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/checksum/ChecksumSyslogMessageModifier.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/checksum/ChecksumSyslogMessageModifier.java new file mode 100644 index 0000000..55b7f6b --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/checksum/ChecksumSyslogMessageModifier.java @@ -0,0 +1,101 @@ +package org.productivity.java.syslog4j.impl.message.modifier.checksum; + +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.message.modifier.AbstractSyslogMessageModifier; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* ChecksumSyslogMessageModifier is an implementation of SyslogMessageModifierIF +* that provides support for Java Checksum algorithms (java.util.zip.Checksum). +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: ChecksumSyslogMessageModifier.java,v 1.5 2010/10/28 05:10:57 cvs Exp $ +*/ +public class ChecksumSyslogMessageModifier extends AbstractSyslogMessageModifier { + private static final long serialVersionUID = -3268914290497005065L; + + protected ChecksumSyslogMessageModifierConfig config = null; + + public static final ChecksumSyslogMessageModifier createCRC32() { + ChecksumSyslogMessageModifier crc32 = new ChecksumSyslogMessageModifier(ChecksumSyslogMessageModifierConfig.createCRC32()); + + return crc32; + } + public static final ChecksumSyslogMessageModifier createADLER32() { + ChecksumSyslogMessageModifier adler32 = new ChecksumSyslogMessageModifier(ChecksumSyslogMessageModifierConfig.createADLER32()); + + return adler32; + } + + public ChecksumSyslogMessageModifier(ChecksumSyslogMessageModifierConfig config) { + super(config); + + this.config = config; + + if (this.config == null) { + throw new SyslogRuntimeException("Checksum config object cannot be null"); + } + + if (this.config.getChecksum() == null) { + throw new SyslogRuntimeException("Checksum object cannot be null"); + } + } + + public ChecksumSyslogMessageModifierConfig getConfig() { + return this.config; + } + + protected void continuousCheckForVerify() { + if (this.config.isContinuous()) { + throw new SyslogRuntimeException(this.getClass().getName() + ".verify(..) does not work with isContinuous() returning true"); + } + + } + + public boolean verify(String message, String hexChecksum) { + continuousCheckForVerify(); + + long checksum = Long.parseLong(hexChecksum,16); + + return verify(message,checksum); + } + + public boolean verify(String message, long checksum) { + continuousCheckForVerify(); + + synchronized(this.config.getChecksum()) { + this.config.getChecksum().reset(); + + byte[] messageBytes = SyslogUtility.getBytes(this.config,message); + + this.config.getChecksum().update(messageBytes,0,message.length()); + + return this.config.getChecksum().getValue() == checksum; + } + } + + public String modify(SyslogIF syslog, int facility, int level, String message) { + synchronized(this.config.getChecksum()) { + StringBuffer messageBuffer = new StringBuffer(message); + + byte[] messageBytes = SyslogUtility.getBytes(syslog.getConfig(),message); + + if (!this.config.isContinuous()) { + this.config.getChecksum().reset(); + } + + this.config.getChecksum().update(messageBytes,0,message.length()); + + messageBuffer.append(this.config.getPrefix()); + messageBuffer.append(Long.toHexString(this.config.getChecksum().getValue()).toUpperCase()); + messageBuffer.append(this.config.getSuffix()); + + return messageBuffer.toString(); + } + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/checksum/ChecksumSyslogMessageModifierConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/checksum/ChecksumSyslogMessageModifierConfig.java new file mode 100644 index 0000000..ebf2cc9 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/checksum/ChecksumSyslogMessageModifierConfig.java @@ -0,0 +1,57 @@ +package org.productivity.java.syslog4j.impl.message.modifier.checksum; + +import java.util.zip.Adler32; +import java.util.zip.CRC32; +import java.util.zip.Checksum; + +import org.productivity.java.syslog4j.impl.message.modifier.AbstractSyslogMessageModifierConfig; + +/** +* ChecksumSyslogMessageModifierConfig is an implementation of AbstractSyslogMessageModifierConfig +* that provides configuration for ChecksumSyslogMessageModifier. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: ChecksumSyslogMessageModifierConfig.java,v 1.2 2010/02/04 03:41:38 cvs Exp $ +*/ +public class ChecksumSyslogMessageModifierConfig extends AbstractSyslogMessageModifierConfig { + private static final long serialVersionUID = -8298600135683882489L; + + protected Checksum checksum = null; + protected boolean continuous = false; + + public static final ChecksumSyslogMessageModifierConfig createCRC32() { + ChecksumSyslogMessageModifierConfig crc32 = new ChecksumSyslogMessageModifierConfig(new CRC32()); + + return crc32; + } + + public static final ChecksumSyslogMessageModifierConfig createADLER32() { + ChecksumSyslogMessageModifierConfig adler32 = new ChecksumSyslogMessageModifierConfig(new Adler32()); + + return adler32; + } + + public ChecksumSyslogMessageModifierConfig(Checksum checksum) { + this.checksum = checksum; + } + + public Checksum getChecksum() { + return this.checksum; + } + + public void setChecksum(Checksum checksum) { + this.checksum = checksum; + } + + public boolean isContinuous() { + return continuous; + } + + public void setContinuous(boolean continuous) { + this.continuous = continuous; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/escape/HTMLEntityEscapeSyslogMessageModifier.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/escape/HTMLEntityEscapeSyslogMessageModifier.java new file mode 100644 index 0000000..762ee98 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/escape/HTMLEntityEscapeSyslogMessageModifier.java @@ -0,0 +1,80 @@ +package org.productivity.java.syslog4j.impl.message.modifier.escape; + +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogMessageModifierIF; + +/** +* HTMLEntityEscapeSyslogMessageModifier is an implementation of SyslogMessageModifierIF +* that safely escapes HTML entity characters. +* +*

This modifier is useful for applications that display log content in browsers without +* properly escaping HTML characters.

+* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: HTMLEntityEscapeSyslogMessageModifier.java,v 1.4 2010/10/28 05:10:57 cvs Exp $ +*/ +public class HTMLEntityEscapeSyslogMessageModifier implements SyslogMessageModifierIF { + private static final long serialVersionUID = -8481773209240762293L; + + public static final SyslogMessageModifierIF createDefault() { + return new HTMLEntityEscapeSyslogMessageModifier(); + } + + public String modify(SyslogIF syslog, int facility, int level, String message) { + if (message != null && !"".equals(message.trim())) { + String escapedMessage = escapeHtml(message); + + return escapedMessage; + } + + return message; + } + + public boolean verify(String message) { + // NO-OP + + return true; + } + + /** + * escapeHtml(String) is based partly on the article posted here: http://www.owasp.org/index.php/How_to_perform_HTML_entity_encoding_in_Java + * with the addition of common characters and modifications for Java 1.4 support. + * + * @param message + * @return Returns a message where any HTML entity characters are escaped. + */ + public static String escapeHtml(String message) { + StringBuffer b = new StringBuffer(message.length()); + + for (int i = 0; i < message.length(); i++) { + char ch = message.charAt(i); + + if (ch == '<') { + b.append("<"); + } else if (ch == '>') { + b.append(">"); + } else if (ch == '"') { + b.append("""); + } else if (ch == '\'') { + b.append("'"); + } else if (ch == '&') { + b.append("&"); + } else if (ch >= ' ' && ch <= '~') { + b.append(ch); + } else if (Character.isWhitespace(ch)) { + b.append("&#").append((int) ch).append(";"); + } else if (Character.isISOControl(ch)) { + // Ignore character + } else if (Character.isDefined(ch)) { + b.append("&#").append((int) ch).append(";"); + } + } + + return b.toString(); + } + +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/hash/HashSyslogMessageModifier.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/hash/HashSyslogMessageModifier.java new file mode 100644 index 0000000..300e8ce --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/hash/HashSyslogMessageModifier.java @@ -0,0 +1,132 @@ +package org.productivity.java.syslog4j.impl.message.modifier.hash; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.message.modifier.AbstractSyslogMessageModifier; +import org.productivity.java.syslog4j.util.Base64; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* HashSyslogMessageModifier is an implementation of SyslogMessageModifierIF +* that provides support for Java Cryptographic hashes (MD5, SHA1, SHA256, etc.). +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: HashSyslogMessageModifier.java,v 1.5 2010/10/28 05:10:57 cvs Exp $ +*/ +public class HashSyslogMessageModifier extends AbstractSyslogMessageModifier { + private static final long serialVersionUID = 7335757344826206953L; + + protected HashSyslogMessageModifierConfig config = null; + + public static final HashSyslogMessageModifier createMD5() { + HashSyslogMessageModifier md5 = new HashSyslogMessageModifier(HashSyslogMessageModifierConfig.createMD5()); + + return md5; + } + + public static final HashSyslogMessageModifier createSHA1() { + HashSyslogMessageModifier sha1 = new HashSyslogMessageModifier(HashSyslogMessageModifierConfig.createSHA1()); + + return sha1; + } + + public static final HashSyslogMessageModifier createSHA160() { + return createSHA1(); + } + + public static final HashSyslogMessageModifier createSHA256() { + HashSyslogMessageModifier sha256 = new HashSyslogMessageModifier(HashSyslogMessageModifierConfig.createSHA256()); + + return sha256; + } + + public static final HashSyslogMessageModifier createSHA384() { + HashSyslogMessageModifier sha384 = new HashSyslogMessageModifier(HashSyslogMessageModifierConfig.createSHA384()); + + return sha384; + } + + public static final HashSyslogMessageModifier createSHA512() { + HashSyslogMessageModifier sha512 = new HashSyslogMessageModifier(HashSyslogMessageModifierConfig.createSHA512()); + + return sha512; + } + + public HashSyslogMessageModifier(HashSyslogMessageModifierConfig config) throws SyslogRuntimeException { + super(config); + + this.config = config; + + if (this.config == null) { + throw new SyslogRuntimeException("Hash config object cannot be null"); + } + + if (this.config.getHashAlgorithm() == null) { + throw new SyslogRuntimeException("Hash algorithm cannot be null"); + } + + try { + MessageDigest.getInstance(config.getHashAlgorithm()); + + } catch (NoSuchAlgorithmException nsae){ + throw new SyslogRuntimeException(nsae); + } + } + + protected MessageDigest obtainMessageDigest() { + MessageDigest digest = null; + + try { + digest = MessageDigest.getInstance(this.config.getHashAlgorithm()); + + } catch (NoSuchAlgorithmException nsae) { + throw new SyslogRuntimeException(nsae); + } + + return digest; + } + + public HashSyslogMessageModifierConfig getConfig() { + return this.config; + } + + public String modify(SyslogIF syslog, int facility, int level, String message) { + byte[] messageBytes = SyslogUtility.getBytes(syslog.getConfig(),message); + + MessageDigest digest = obtainMessageDigest(); + byte[] digestBytes = digest.digest(messageBytes); + + String digestString = Base64.encodeBytes(digestBytes,Base64.DONT_BREAK_LINES); + + StringBuffer buffer = new StringBuffer(message); + + buffer.append(this.config.getPrefix()); + buffer.append(digestString); + buffer.append(this.config.getSuffix()); + + return buffer.toString(); + } + + public boolean verify(String message, String base64Hash) { + byte[] hash = Base64.decode(base64Hash); + + return verify(message,hash); + } + + public boolean verify(String message, byte[] hash) { + byte[] messageBytes = SyslogUtility.getBytes(this.config,message); + + MessageDigest digest = obtainMessageDigest(); + byte[] digestBytes = digest.digest(messageBytes); + + return Arrays.equals(digestBytes,hash); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/hash/HashSyslogMessageModifierConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/hash/HashSyslogMessageModifierConfig.java new file mode 100644 index 0000000..4dd0c8d --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/hash/HashSyslogMessageModifierConfig.java @@ -0,0 +1,66 @@ +package org.productivity.java.syslog4j.impl.message.modifier.hash; + +import org.productivity.java.syslog4j.impl.message.modifier.AbstractSyslogMessageModifierConfig; + +/** +* HashSyslogMessageModifierConfig is an implementation of AbstractSyslogMessageModifierConfig +* that provides configuration for HashSyslogMessageModifier. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: HashSyslogMessageModifierConfig.java,v 1.1 2008/11/10 04:38:37 cvs Exp $ +*/ +public class HashSyslogMessageModifierConfig extends AbstractSyslogMessageModifierConfig { + private static final long serialVersionUID = -3148300281439874231L; + + protected String hashAlgorithm = null; + + public static final HashSyslogMessageModifierConfig createMD5() { + HashSyslogMessageModifierConfig md5 = new HashSyslogMessageModifierConfig("MD5"); + + return md5; + } + + public static final HashSyslogMessageModifierConfig createSHA1() { + HashSyslogMessageModifierConfig sha1 = new HashSyslogMessageModifierConfig("SHA1"); + + return sha1; + } + + public static final HashSyslogMessageModifierConfig createSHA160() { + return createSHA1(); + } + + public static final HashSyslogMessageModifierConfig createSHA256() { + HashSyslogMessageModifierConfig sha256 = new HashSyslogMessageModifierConfig("SHA-256"); + + return sha256; + } + + public static final HashSyslogMessageModifierConfig createSHA384() { + HashSyslogMessageModifierConfig sha384 = new HashSyslogMessageModifierConfig("SHA-384"); + + return sha384; + } + + public static final HashSyslogMessageModifierConfig createSHA512() { + HashSyslogMessageModifierConfig sha512 = new HashSyslogMessageModifierConfig("SHA-512"); + + return sha512; + } + + public HashSyslogMessageModifierConfig(String hashAlgorithm) { + this.hashAlgorithm = hashAlgorithm; + } + + public String getHashAlgorithm() { + return this.hashAlgorithm; + } + + public void setHashAlgorithm(String hashAlgorithm) { + this.hashAlgorithm = hashAlgorithm; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/mac/MacSyslogMessageModifier.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/mac/MacSyslogMessageModifier.java new file mode 100644 index 0000000..492ec7b --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/mac/MacSyslogMessageModifier.java @@ -0,0 +1,120 @@ +package org.productivity.java.syslog4j.impl.message.modifier.mac; + +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +import javax.crypto.Mac; + +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.message.modifier.AbstractSyslogMessageModifier; +import org.productivity.java.syslog4j.util.Base64; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* MacSyslogMessageModifier is an implementation of SyslogMessageModifierIF +* that provides support for Java Cryptographic signed hashes (HmacSHA1, etc.) +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: MacSyslogMessageModifier.java,v 1.5 2010/10/28 05:10:57 cvs Exp $ +*/ +public class MacSyslogMessageModifier extends AbstractSyslogMessageModifier { + private static final long serialVersionUID = 5054979194802197540L; + + protected MacSyslogMessageModifierConfig config = null; + + protected Mac mac = null; + + public MacSyslogMessageModifier(MacSyslogMessageModifierConfig config) throws SyslogRuntimeException { + super(config); + + this.config = config; + + try { + this.mac = Mac.getInstance(config.getMacAlgorithm()); + this.mac.init(config.getKey()); + + } catch (NoSuchAlgorithmException nsae) { + throw new SyslogRuntimeException(nsae); + + } catch (InvalidKeyException ike) { + throw new SyslogRuntimeException(ike); + } + } + + public static MacSyslogMessageModifier createHmacSHA1(Key key) { + return new MacSyslogMessageModifier(MacSyslogMessageModifierConfig.createHmacSHA1(key)); + } + + public static MacSyslogMessageModifier createHmacSHA1(String base64Key) { + return new MacSyslogMessageModifier(MacSyslogMessageModifierConfig.createHmacSHA1(base64Key)); + } + + public static MacSyslogMessageModifier createHmacSHA256(Key key) { + return new MacSyslogMessageModifier(MacSyslogMessageModifierConfig.createHmacSHA256(key)); + } + + public static MacSyslogMessageModifier createHmacSHA256(String base64Key) { + return new MacSyslogMessageModifier(MacSyslogMessageModifierConfig.createHmacSHA256(base64Key)); + } + + public static MacSyslogMessageModifier createHmacSHA512(Key key) { + return new MacSyslogMessageModifier(MacSyslogMessageModifierConfig.createHmacSHA512(key)); + } + + public static MacSyslogMessageModifier createHmacSHA512(String base64Key) { + return new MacSyslogMessageModifier(MacSyslogMessageModifierConfig.createHmacSHA512(base64Key)); + } + + public static MacSyslogMessageModifier createHmacMD5(Key key) { + return new MacSyslogMessageModifier(MacSyslogMessageModifierConfig.createHmacMD5(key)); + } + + public static MacSyslogMessageModifier createHmacMD5(String base64Key) { + return new MacSyslogMessageModifier(MacSyslogMessageModifierConfig.createHmacMD5(base64Key)); + } + + public MacSyslogMessageModifierConfig getConfig() { + return this.config; + } + + public String modify(SyslogIF syslog, int facility, int level, String message) { + synchronized(this.mac) { + byte[] messageBytes = SyslogUtility.getBytes(syslog.getConfig(),message); + + StringBuffer buffer = new StringBuffer(message); + + byte[] macBytes = this.mac.doFinal(messageBytes); + + String macString = Base64.encodeBytes(macBytes,Base64.DONT_BREAK_LINES); + + buffer.append(this.config.getPrefix()); + buffer.append(macString); + buffer.append(this.config.getSuffix()); + + return buffer.toString(); + } + } + + public boolean verify(String message, String base64Signature) { + byte[] signature = Base64.decode(base64Signature); + + return verify(message,signature); + } + + public boolean verify(String message, byte[] signature) { + synchronized(this.mac) { + byte[] messageBytes = SyslogUtility.getBytes(this.config,message); + + byte[] macBytes = this.mac.doFinal(messageBytes); + + return Arrays.equals(macBytes,signature); + } + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/mac/MacSyslogMessageModifierConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/mac/MacSyslogMessageModifierConfig.java new file mode 100644 index 0000000..ce055da --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/mac/MacSyslogMessageModifierConfig.java @@ -0,0 +1,108 @@ +package org.productivity.java.syslog4j.impl.message.modifier.mac; + +import java.security.Key; + +import javax.crypto.spec.SecretKeySpec; + +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.message.modifier.AbstractSyslogMessageModifierConfig; +import org.productivity.java.syslog4j.util.Base64; + +/** +* MacSyslogMessageModifierConfig is an implementation of AbstractSyslogMessageModifierConfig +* that provides configuration for HashSyslogMessageModifier. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: MacSyslogMessageModifierConfig.java,v 1.3 2009/04/17 02:37:04 cvs Exp $ +*/ +public class MacSyslogMessageModifierConfig extends AbstractSyslogMessageModifierConfig { + private static final long serialVersionUID = 4524180892377960695L; + + protected String macAlgorithm = null; + protected String keyAlgorithm = null; + protected Key key = null; + + public MacSyslogMessageModifierConfig(String macAlgorithm, String keyAlgorithm, Key key) { + this.macAlgorithm = macAlgorithm; + this.keyAlgorithm = keyAlgorithm; + this.key = key; + } + + public MacSyslogMessageModifierConfig(String macAlgorithm, String keyAlgorithm, byte[] keyBytes) { + this.macAlgorithm = macAlgorithm; + this.keyAlgorithm = keyAlgorithm; + + try { + this.key = new SecretKeySpec(keyBytes,keyAlgorithm); + + } catch (IllegalArgumentException iae) { + throw new SyslogRuntimeException(iae); + } + } + + public MacSyslogMessageModifierConfig(String macAlgorithm, String keyAlgorithm, String base64Key) { + this.macAlgorithm = macAlgorithm; + this.keyAlgorithm = keyAlgorithm; + + byte[] keyBytes = Base64.decode(base64Key); + + try { + this.key = new SecretKeySpec(keyBytes,keyAlgorithm); + + } catch (IllegalArgumentException iae) { + throw new SyslogRuntimeException(iae); + } + } + + public static MacSyslogMessageModifierConfig createHmacSHA1(Key key) { + return new MacSyslogMessageModifierConfig("HmacSHA1","SHA1",key); + } + + public static MacSyslogMessageModifierConfig createHmacSHA1(String base64Key) { + return new MacSyslogMessageModifierConfig("HmacSHA1","SHA1",base64Key); + } + + public static MacSyslogMessageModifierConfig createHmacSHA256(Key key) { + return new MacSyslogMessageModifierConfig("HmacSHA256","SHA-256",key); + } + + public static MacSyslogMessageModifierConfig createHmacSHA256(String base64Key) { + return new MacSyslogMessageModifierConfig("HmacSHA256","SHA-256",base64Key); + } + + public static MacSyslogMessageModifierConfig createHmacSHA512(Key key) { + return new MacSyslogMessageModifierConfig("HmacSHA512","SHA-512",key); + } + + public static MacSyslogMessageModifierConfig createHmacSHA512(String base64Key) { + return new MacSyslogMessageModifierConfig("HmacSHA512","SHA-512",base64Key); + } + + public static MacSyslogMessageModifierConfig createHmacMD5(Key key) { + return new MacSyslogMessageModifierConfig("HmacMD5","MD5",key); + } + + public static MacSyslogMessageModifierConfig createHmacMD5(String base64Key) { + return new MacSyslogMessageModifierConfig("HmacMD5","MD5",base64Key); + } + + public String getMacAlgorithm() { + return this.macAlgorithm; + } + + public String getKeyAlgorithm() { + return this.keyAlgorithm; + } + + public Key getKey() { + return this.key; + } + + public void setKey(Key key) { + this.key = key; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifier.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifier.java new file mode 100644 index 0000000..4ac5364 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifier.java @@ -0,0 +1,101 @@ +package org.productivity.java.syslog4j.impl.message.modifier.sequential; + +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogMessageModifierIF; + +/** +* SequentialSyslogMessageModifier is an implementation of SyslogMessageModifierIF +* that adds an incremented number at the end. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SequentialSyslogMessageModifier.java,v 1.8 2010/11/28 04:43:31 cvs Exp $ +*/ +public class SequentialSyslogMessageModifier implements SyslogMessageModifierIF { + private static final long serialVersionUID = 6107735010240030785L; + + protected SequentialSyslogMessageModifierConfig config = null; + + protected long currentSequence[] = new long[LEVEL_DEBUG + 1]; + + public static final SequentialSyslogMessageModifier createDefault() { + SequentialSyslogMessageModifier modifier = new SequentialSyslogMessageModifier(SequentialSyslogMessageModifierConfig.createDefault()); + + return modifier; + } + + public SequentialSyslogMessageModifier(SequentialSyslogMessageModifierConfig config) { + this.config = config; + + for(int i=0; i<(LEVEL_DEBUG + 1); i++) { + this.currentSequence[i] = config.getFirstNumber(); + } + } + + protected String pad(long number) { + StringBuffer buffer = new StringBuffer(Long.toString(number)); + + while (buffer.length() < this.config.getLastNumberDigits()) { + buffer.insert(0,this.config.getPadChar()); + } + + return buffer.toString(); + } + + public void setNextSequence(int level, long nextSequence) { + if (nextSequence >= this.config.getFirstNumber() && nextSequence < this.config.getLastNumber()) { + synchronized(this) { + this.currentSequence[level] = nextSequence; + } + } + } + + protected String nextSequence(int level) { + long sequence = -1; + + synchronized(this) { + sequence = this.currentSequence[level]; + + if (this.currentSequence[level] >= this.config.getLastNumber()) { + this.currentSequence[level] = this.config.getFirstNumber(); + + } else { + this.currentSequence[level]++; + } + } + + String _sequence = null; + + if (this.config.isUsePadding()) { + _sequence = pad(sequence); + + } else { + _sequence = Long.toString(sequence); + } + + return _sequence; + } + + public SequentialSyslogMessageModifierConfig getConfig() { + return this.config; + } + + public String modify(SyslogIF syslog, int facility, int level, String message) { + StringBuffer buffer = new StringBuffer(message); + + buffer.append(this.config.getPrefix()); + buffer.append(nextSequence(level)); + buffer.append(this.config.getSuffix()); + + return buffer.toString(); + } + + public boolean verify(String message) { + // NO-OP + + return true; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifierConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifierConfig.java new file mode 100644 index 0000000..307ae86 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifierConfig.java @@ -0,0 +1,74 @@ +package org.productivity.java.syslog4j.impl.message.modifier.sequential; + +import org.productivity.java.syslog4j.impl.message.modifier.AbstractSyslogMessageModifierConfig; + +/** +* SequentialSyslogMessageModifierConfig is an implementation of AbstractSyslogMessageModifierConfig +* that provides configuration for SequentialSyslogMessageModifier. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SequentialSyslogMessageModifierConfig.java,v 1.4 2009/03/29 17:38:58 cvs Exp $ +*/ +public class SequentialSyslogMessageModifierConfig extends AbstractSyslogMessageModifierConfig { + private static final long serialVersionUID = 1570930406228960303L; + + protected long firstNumber = SYSLOG_SEQUENTIAL_MESSAGE_MODIFIER_FIRST_NUMBER_DEFAULT; + protected long lastNumber = SYSLOG_SEQUENTIAL_MESSAGE_MODIFIER_LAST_NUMBER_DEFAULT; + protected char padChar = SYSLOG_SEQUENTIAL_MESSAGE_MODIFIER_PAD_CHAR_DEFAULT; + protected boolean usePadding = SYSLOG_SEQUENTIAL_MESSAGE_MODIFIER_USE_PADDING_DEFAULT; + + public static final SequentialSyslogMessageModifierConfig createDefault() { + SequentialSyslogMessageModifierConfig modifierConfig = new SequentialSyslogMessageModifierConfig(); + + return modifierConfig; + } + + public SequentialSyslogMessageModifierConfig() { + setPrefix(SYSLOG_SEQUENTIAL_MESSAGE_MODIFIER_PREFIX_DEFAULT); + setSuffix(SYSLOG_SEQUENTIAL_MESSAGE_MODIFIER_SUFFIX_DEFAULT); + } + + public long getLastNumberDigits() { + return Long.toString(this.lastNumber).length(); + } + + public long getFirstNumber() { + return this.firstNumber; + } + + public void setFirstNumber(long firstNumber) { + if (firstNumber < this.lastNumber) { + this.firstNumber = firstNumber; + } + } + + public long getLastNumber() { + return this.lastNumber; + } + + public void setLastNumber(long lastNumber) { + if (lastNumber > this.firstNumber) { + this.lastNumber = lastNumber; + } + } + + public boolean isUsePadding() { + return this.usePadding; + } + + public void setUsePadding(boolean usePadding) { + this.usePadding = usePadding; + } + + public char getPadChar() { + return this.padChar; + } + + public void setPadChar(char padChar) { + this.padChar = padChar; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/text/PrefixSyslogMessageModifier.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/text/PrefixSyslogMessageModifier.java new file mode 100644 index 0000000..32afee0 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/text/PrefixSyslogMessageModifier.java @@ -0,0 +1,59 @@ +package org.productivity.java.syslog4j.impl.message.modifier.text; + +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogMessageModifierIF; + +/** +* PrefixSyslogMessageModifier is an implementation of SyslogMessageModifierIF +* that provides support for adding static text to the beginning of a Syslog message. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: PrefixSyslogMessageModifier.java,v 1.5 2010/10/28 05:10:57 cvs Exp $ +*/ +public class PrefixSyslogMessageModifier implements SyslogMessageModifierIF { + private static final long serialVersionUID = 6718826215583513972L; + + protected String prefix = null; + protected String delimiter = " "; + + public PrefixSyslogMessageModifier() { + // + } + + public PrefixSyslogMessageModifier(String prefix) { + this.prefix = prefix; + } + + public PrefixSyslogMessageModifier(String prefix, String delimiter) { + this.prefix = prefix; + if (delimiter != null) { + this.delimiter = delimiter; + } + } + + public String getPrefix() { + return this.prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public String modify(SyslogIF syslog, int facility, int level, String message) { + if (this.prefix == null || "".equals(this.prefix.trim())) { + return message; + } + + return this.prefix + this.delimiter + message; + } + + public boolean verify(String message) { + // NO-OP + + return true; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/text/StringCaseSyslogMessageModifier.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/text/StringCaseSyslogMessageModifier.java new file mode 100644 index 0000000..bc76773 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/text/StringCaseSyslogMessageModifier.java @@ -0,0 +1,58 @@ +package org.productivity.java.syslog4j.impl.message.modifier.text; + +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogMessageModifierIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; + +/** +* StringCaseSyslogMessageModifier is an implementation of SyslogMessageModifierIF +* that provides support for shifting a Syslog message to all upper case or all +* lower case. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: StringCaseSyslogMessageModifier.java,v 1.3 2010/10/28 05:10:57 cvs Exp $ +*/ +public class StringCaseSyslogMessageModifier implements SyslogMessageModifierIF { + private static final long serialVersionUID = 8383234811585957460L; + + public static final byte LOWER_CASE = 0; + public static final byte UPPER_CASE = 1; + + public static final StringCaseSyslogMessageModifier LOWER = new StringCaseSyslogMessageModifier(LOWER_CASE); + public static final StringCaseSyslogMessageModifier UPPER = new StringCaseSyslogMessageModifier(UPPER_CASE); + + protected byte stringCase = LOWER_CASE; + + public StringCaseSyslogMessageModifier(byte stringCase) { + this.stringCase = stringCase; + + if (stringCase < LOWER_CASE || stringCase > UPPER_CASE) { + throw new SyslogRuntimeException("stringCase must be LOWER_CASE (0) or UPPER_CASE (1)"); + } + } + + public String modify(SyslogIF syslog, int facility, int level, String message) { + String _message = message; + + if (message != null) { + if (this.stringCase == LOWER_CASE) { + _message = _message.toLowerCase(); + + } else if (this.stringCase == UPPER_CASE) { + _message = _message.toUpperCase(); + } + } + + return _message; + } + + public boolean verify(String message) { + // NO-OP + + return true; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/text/SuffixSyslogMessageModifier.java b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/text/SuffixSyslogMessageModifier.java new file mode 100644 index 0000000..7f20a23 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/modifier/text/SuffixSyslogMessageModifier.java @@ -0,0 +1,59 @@ +package org.productivity.java.syslog4j.impl.message.modifier.text; + +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogMessageModifierIF; + +/** +* SuffixSyslogMessageModifier is an implementation of SyslogMessageModifierIF +* that provides support for adding static text to the end of a Syslog message. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SuffixSyslogMessageModifier.java,v 1.5 2010/10/28 05:10:57 cvs Exp $ +*/ +public class SuffixSyslogMessageModifier implements SyslogMessageModifierIF { + private static final long serialVersionUID = 7160593302741507576L; + + protected String suffix = null; + protected String delimiter = " "; + + public SuffixSyslogMessageModifier() { + // + } + + public SuffixSyslogMessageModifier(String suffix) { + this.suffix = suffix; + } + + public SuffixSyslogMessageModifier(String suffix, String delimiter) { + this.suffix = suffix; + if (delimiter != null) { + this.delimiter = delimiter; + } + } + + public String getSuffix() { + return this.suffix; + } + + public void setSuffix(String suffix) { + this.suffix = suffix; + } + + public String modify(SyslogIF syslog, int facility, int level, String message) { + if (this.suffix == null || "".equals(this.suffix.trim())) { + return message; + } + + return message + this.delimiter + this.suffix; + } + + public boolean verify(String message) { + // NO-OP + + return true; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/pci/PCISyslogMessage.java b/src/main/java/org/productivity/java/syslog4j/impl/message/pci/PCISyslogMessage.java new file mode 100644 index 0000000..78afb42 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/pci/PCISyslogMessage.java @@ -0,0 +1,256 @@ +package org.productivity.java.syslog4j.impl.message.pci; + +import java.util.Date; +import java.util.Map; + +import org.productivity.java.syslog4j.impl.message.AbstractSyslogMessage; + +/** +* PCISyslogMessage provides support for audit trails defined by section +* 10.3 of the PCI Data Security Standard (PCI DSS) versions 1.1 and 1.2. +* +*

More information on the PCI DSS specification is available here:

+* +*

https://www.pcisecuritystandards.org/security_standards/pci_dss.shtml

+* +*

The PCI DSS specification is Copyright 2008 PCI Security Standards +* Council LLC.

+* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: PCISyslogMessage.java,v 1.3 2008/11/14 04:32:00 cvs Exp $ +*/ +public class PCISyslogMessage extends AbstractSyslogMessage implements PCISyslogMessageIF { + private static final long serialVersionUID = 3571696218386879119L; + + public static final String USER_ID = "userId"; + public static final String EVENT_TYPE = "eventType"; + public static final String DATE = "date"; + public static final String TIME = "time"; + public static final String STATUS = "status"; + public static final String ORIGINATION = "origination"; + public static final String AFFECTED_RESOURCE = "affectedResource"; + + protected String userId = UNDEFINED; // 10.3.1 "User Identification" + protected String eventType = UNDEFINED; // 10.3.2 "Type of event" + protected String date = null; // 10.3.3 "Date and time" (date) + protected String time = null; // 10.3.3 "Date and time" (time) + protected String status = UNDEFINED; // 10.3.4 "Success or failure indication" + protected String origination = null; // 10.3.5 "Origination of Event" + protected String affectedResource = UNDEFINED; // 10.3.6 "Identity or name of affected data, system component, or resource" + + public PCISyslogMessage() { + // + } + + public PCISyslogMessage(PCISyslogMessageIF message) { + init(message); + } + + public PCISyslogMessage(Map fields) { + init(fields); + } + + protected void init(PCISyslogMessageIF message) { + this.userId = message.getUserId(); + this.eventType = message.getEventType(); + this.date = message.getDate(); + this.time = message.getTime(); + this.status = message.getStatus(); + this.origination = message.getOrigination(); + this.affectedResource = message.getAffectedResource(); + } + + protected void init(Map fields) { + if (fields.containsKey(USER_ID)) { this.userId = (String) fields.get(USER_ID); }; + if (fields.containsKey(EVENT_TYPE)) { this.eventType = (String) fields.get(EVENT_TYPE); }; + if (fields.containsKey(DATE) && fields.get(DATE) instanceof String) { this.date = (String) fields.get(DATE); }; + if (fields.containsKey(DATE) && fields.get(DATE) instanceof Date) { setDate((Date) fields.get(DATE)); }; + if (fields.containsKey(TIME)) { this.time = (String) fields.get(TIME); }; + if (fields.containsKey(STATUS)) { this.status = (String) fields.get(STATUS); }; + if (fields.containsKey(ORIGINATION)) { this.origination = (String) fields.get(ORIGINATION); }; + if (fields.containsKey(AFFECTED_RESOURCE)) { this.affectedResource = (String) fields.get(AFFECTED_RESOURCE); }; + } + + public PCISyslogMessage(String userId, String eventType, String status, String affectedResource) { + this.userId = userId; + this.eventType = eventType; + this.status = status; + this.affectedResource = affectedResource; + } + + public PCISyslogMessage(String userId, String eventType, String status, String origination, String affectedResource) { + this.userId = userId; + this.eventType = eventType; + this.status = status; + this.origination = origination; + this.affectedResource = affectedResource; + } + + public PCISyslogMessage(String userId, String eventType, String date, String time, String status, String affectedResource) { + this.userId = userId; + this.eventType = eventType; + this.date = date; + this.time = time; + this.status = status; + this.affectedResource = affectedResource; + } + + public PCISyslogMessage(String userId, String eventType, String date, String time, String status, String origination, String affectedResource) { + this.userId = userId; + this.eventType = eventType; + this.date = date; + this.time = time; + this.status = status; + this.origination = origination; + this.affectedResource = affectedResource; + } + + public PCISyslogMessage(String userId, String eventType, Date date, String status, String affectedResource) { + this.userId = userId; + this.eventType = eventType; + + String[] dateAndTime = generateDateAndTime(date); + this.date = dateAndTime[0]; + this.time = dateAndTime[1]; + + this.status = status; + this.affectedResource = affectedResource; + } + + public PCISyslogMessage(String userId, String eventType, Date date, String status, String origination, String affectedResource) { + this.userId = userId; + this.eventType = eventType; + + String[] dateAndTime = generateDateAndTime(date); + this.date = dateAndTime[0]; + this.time = dateAndTime[1]; + + this.status = status; + this.origination = origination; + this.affectedResource = affectedResource; + } + + public String getUserId() { + if (nullOrEmpty(this.userId)) { + return UNDEFINED; + } + + return this.userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getEventType() { + if (nullOrEmpty(this.eventType)) { + return UNDEFINED; + } + + return this.eventType; + } + + public void setEventType(String eventType) { + this.eventType = eventType; + } + + public String getDate() { + if (nullOrEmpty(this.date)) { + String dateNow = generateDate(); + + return dateNow; + } + + return this.date; + } + + public void setDate(String date) { + this.date = date; + } + + public void setDate(Date date) { + String[] d = generateDateAndTime(date); + + this.date = d[0]; + this.time = d[1]; + } + + public String getTime() { + if (nullOrEmpty(this.time)) { + String timeNow = generateTime(); + + return timeNow; + } + + return this.time; + } + + public void setTime(String time) { + this.time = time; + } + + public String getStatus() { + if (nullOrEmpty(this.status)) { + return UNDEFINED; + } + + return this.status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getOrigination() { + if (nullOrEmpty(this.origination)) { + String originationHere = generateLocalHostName(); + + return originationHere; + } + + return this.origination; + } + + public void setOrigination(String origination) { + this.origination = origination; + } + + public String getAffectedResource() { + if (nullOrEmpty(this.affectedResource)) { + return UNDEFINED; + } + + return this.affectedResource; + } + + public void setAffectedResource(String affectedResource) { + this.affectedResource = affectedResource; + } + + public String createMessage() { + StringBuffer buffer = new StringBuffer(); + + char delimiter = getDelimiter(); + String replaceDelimiter = getReplaceDelimiter(); + + buffer.append(replaceDelimiter(USER_ID,getUserId(),delimiter,replaceDelimiter)); + buffer.append(delimiter); + buffer.append(replaceDelimiter(EVENT_TYPE,getEventType(),delimiter,replaceDelimiter)); + buffer.append(delimiter); + buffer.append(replaceDelimiter(DATE,getDate(),delimiter,replaceDelimiter)); + buffer.append(delimiter); + buffer.append(replaceDelimiter(TIME,getTime(),delimiter,replaceDelimiter)); + buffer.append(delimiter); + buffer.append(replaceDelimiter(STATUS,getStatus(),delimiter,replaceDelimiter)); + buffer.append(delimiter); + buffer.append(replaceDelimiter(ORIGINATION,getOrigination(),delimiter,replaceDelimiter)); + buffer.append(delimiter); + buffer.append(replaceDelimiter(AFFECTED_RESOURCE,getAffectedResource(),delimiter,replaceDelimiter)); + + return buffer.toString(); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/pci/PCISyslogMessageIF.java b/src/main/java/org/productivity/java/syslog4j/impl/message/pci/PCISyslogMessageIF.java new file mode 100644 index 0000000..31499d6 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/pci/PCISyslogMessageIF.java @@ -0,0 +1,30 @@ +package org.productivity.java.syslog4j.impl.message.pci; + +/** +* PCISyslogMessageIF provides a definition of the fields for audit trails +* defined by section 10.3 of the PCI Data Security Standard (PCI DSS) +* versions 1.1 and 1.2. +* +*

More information on the PCI DSS specification is available here:

+* +*

https://www.pcisecuritystandards.org/security_standards/pci_dss.shtml

+* +*

The PCI DSS specification is Copyright 2008 PCI Security Standards +* Council LLC.

+* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: PCISyslogMessageIF.java,v 1.1 2008/11/10 04:38:37 cvs Exp $ +*/ +public interface PCISyslogMessageIF { + public String getUserId(); + public String getEventType(); + public String getDate(); + public String getTime(); + public String getStatus(); + public String getOrigination(); + public String getAffectedResource(); +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/processor/AbstractSyslogMessageProcessor.java b/src/main/java/org/productivity/java/syslog4j/impl/message/processor/AbstractSyslogMessageProcessor.java new file mode 100644 index 0000000..b21c23f --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/processor/AbstractSyslogMessageProcessor.java @@ -0,0 +1,118 @@ +package org.productivity.java.syslog4j.impl.message.processor; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogMessageProcessorIF; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* AbstractSyslogMessageProcessor provides the ability to split a syslog message +* into multiple messages when the message is greater than the syslog +* maximum message length (1024 bytes including the header). +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractSyslogMessageProcessor.java,v 1.2 2010/11/28 04:15:18 cvs Exp $ +*/ +public abstract class AbstractSyslogMessageProcessor implements SyslogMessageProcessorIF, SyslogConstants { + private static final long serialVersionUID = -5413127301924500938L; + protected String localName = null; + + public AbstractSyslogMessageProcessor() { + this.localName = SyslogUtility.getLocalName(); + } + + public byte[] createPacketData(byte[] header, byte[] message, int start, int length) { + return createPacketData(header,message,start,length,null,null); + } + + public byte[] createPacketData(byte[] header, byte[] message, int start, int length, byte[] splitBeginText, byte[] splitEndText) { + if (header == null || message == null || start < 0 || length < 0) { + return null; + } + + int dataLength = header.length + length; + + if (splitBeginText != null) { + dataLength += splitBeginText.length; + } + if (splitEndText != null) { + dataLength += splitEndText.length; + } + + byte[] data = new byte[dataLength]; + + System.arraycopy(header,0,data,0,header.length); + int pos = header.length; + + if (splitBeginText != null) { + System.arraycopy(splitBeginText,0,data,pos,splitBeginText.length); + pos += splitBeginText.length; + } + + System.arraycopy(message,start,data,pos,length); + pos += length; + + if (splitEndText != null) { + System.arraycopy(splitEndText,0,data,pos,splitEndText.length); + } + + return data; + } + + protected void appendPriority(StringBuffer buffer, int facility, int level) { + int priority = facility | level; + + buffer.append("<"); + buffer.append(priority); + buffer.append(">"); + } + + protected void appendLocalTimestamp(StringBuffer buffer) { + SimpleDateFormat dateFormat = new SimpleDateFormat(SYSLOG_DATEFORMAT,Locale.ENGLISH); + + String datePrefix = dateFormat.format(new Date()); + + int pos = buffer.length() + 4; + + buffer.append(datePrefix); + + // RFC 3164 requires leading space for days 1-9 + if (buffer.charAt(pos) == '0') { + buffer.setCharAt(pos,' '); + } + } + + protected void appendLocalName(StringBuffer buffer, String localName) { + if (localName != null) { + buffer.append(localName); + + } else { + buffer.append(this.localName); + } + + buffer.append(' '); + } + + public String createSyslogHeader(int facility, int level, String localName, boolean sendLocalTimestamp, boolean sendLocalName) { + StringBuffer buffer = new StringBuffer(); + + appendPriority(buffer,facility,level); + + if (sendLocalTimestamp) { + appendLocalTimestamp(buffer); + } + + if (sendLocalName) { + appendLocalName(buffer,localName); + } + + return buffer.toString(); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/processor/SyslogMessageProcessor.java b/src/main/java/org/productivity/java/syslog4j/impl/message/processor/SyslogMessageProcessor.java new file mode 100644 index 0000000..da3ce3d --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/processor/SyslogMessageProcessor.java @@ -0,0 +1,35 @@ +package org.productivity.java.syslog4j.impl.message.processor; + + +/** +* SyslogMessageProcessor wraps AbstractSyslogMessageProcessor. +* +*

Those wishing to replace (or improve upon) this implementation +* can write a custom SyslogMessageProcessorIF and set it per +* instance via the SyslogIF.setMessageProcessor(..) method or set it globally +* via the SyslogMessageProcessor.setDefault(..) method.

+* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogMessageProcessor.java,v 1.7 2010/02/04 03:41:37 cvs Exp $ +*/ +public class SyslogMessageProcessor extends AbstractSyslogMessageProcessor { + private static final long serialVersionUID = -4232803978024990353L; + + private static final SyslogMessageProcessor INSTANCE = new SyslogMessageProcessor(); + + protected static SyslogMessageProcessor defaultInstance = INSTANCE; + + public static void setDefault(SyslogMessageProcessor messageProcessor) { + if (messageProcessor != null) { + defaultInstance = messageProcessor; + } + } + + public static SyslogMessageProcessor getDefault() { + return defaultInstance; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/processor/structured/StructuredSyslogMessageProcessor.java b/src/main/java/org/productivity/java/syslog4j/impl/message/processor/structured/StructuredSyslogMessageProcessor.java new file mode 100644 index 0000000..0d5b769 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/processor/structured/StructuredSyslogMessageProcessor.java @@ -0,0 +1,106 @@ +package org.productivity.java.syslog4j.impl.message.processor.structured; + +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; +import org.productivity.java.syslog4j.impl.message.processor.AbstractSyslogMessageProcessor; +import org.productivity.java.syslog4j.impl.message.structured.StructuredSyslogMessage; + +/** + * SyslogStructuredMessageProcessor extends SyslogMessageProcessor's ability to + * split a syslog message into multiple messages when the message is greater + * than the syslog maximum message length (1024 bytes including the header). It + * adds support for structured syslog messages as specified by + * draft-ietf-syslog-protocol-23. More information here: + * + *

http://tools.ietf.org/html/draft-ietf-syslog-protocol-23

+ * + *

Those wishing to replace (or improve upon) this implementation + * can write a custom SyslogMessageProcessorIF and set it per + * instance via the SyslogIF.setStructuredMessageProcessor(..) method or set it globally + * via the StructuredSyslogMessageProcessor.setDefault(..) method.

+ * + *

+ * Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy of the + * LGPL license is available in the META-INF folder in all distributions of + * Syslog4j and in the base directory of the "doc" ZIP. + *

+ * + * @author Manish Motwani + * @version $Id: StructuredSyslogMessageProcessor.java,v 1.4 2011/01/11 05:11:13 cvs Exp $ + */ +public class StructuredSyslogMessageProcessor extends AbstractSyslogMessageProcessor { + private static final long serialVersionUID = -1563777226913475257L; + + public static String VERSION = "1"; + + private static final StructuredSyslogMessageProcessor INSTANCE = new StructuredSyslogMessageProcessor(); + protected static StructuredSyslogMessageProcessor defaultInstance = INSTANCE; + + private String applicationName = STRUCTURED_DATA_APP_NAME_DEFAULT_VALUE; + private String processId = STRUCTURED_DATA_PROCESS_ID_DEFAULT_VALUE; + + private DateTimeFormatter dateTimeFormatter = ISODateTimeFormat.dateTime(); + + public static void setDefault(StructuredSyslogMessageProcessor messageProcessor) { + if (messageProcessor != null) { + defaultInstance = messageProcessor; + } + } + + public static StructuredSyslogMessageProcessor getDefault() { + return defaultInstance; + } + + public StructuredSyslogMessageProcessor() { + super(); + } + + public StructuredSyslogMessageProcessor(final String applicationName) { + super(); + this.applicationName = applicationName; + } + + public DateTimeFormatter getDateTimeFormatter() { + return dateTimeFormatter; + } + + public void setDateTimeFormatter(DateTimeFormatter dateTimeFormatter) { + this.dateTimeFormatter = dateTimeFormatter; + } + + public String getApplicationName() { + return this.applicationName; + } + + public void setApplicationName(String applicationName) { + this.applicationName = applicationName; + } + + public String getProcessId() { + return this.processId; + } + + public void setProcessId(String processId) { + this.processId = processId; + } + + public String createSyslogHeader(final int facility, final int level, String localName, final boolean sendLocalTimestamp, final boolean sendLocalName) { + final StringBuffer buffer = new StringBuffer(); + + appendPriority(buffer,facility,level); + buffer.append(VERSION); + buffer.append(' '); + + getDateTimeFormatter().printTo(buffer,System.currentTimeMillis()); + buffer.append(' '); + + appendLocalName(buffer,localName); + + buffer.append(StructuredSyslogMessage.nilProtect(this.applicationName)) + .append(' '); + + buffer.append(StructuredSyslogMessage.nilProtect(this.processId)).append(' '); + + return buffer.toString(); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessage.java b/src/main/java/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessage.java new file mode 100644 index 0000000..2f71909 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessage.java @@ -0,0 +1,391 @@ +package org.productivity.java.syslog4j.impl.message.structured; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.impl.message.AbstractSyslogMessage; + +/** + * SyslogStructuredMessage extends AbstractSyslogMessage's ability to provide + * support for turning POJO (Plain Ol' Java Objects) into Syslog messages. It + * adds support for structured syslog messages as specified by + * draft-ietf-syslog-protocol-23. More information here: + * + *

+ * http://tools.ietf.org/html/draft-ietf-syslog-protocol-23#section-6 + *

+ * + *

+ * Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy of the + * LGPL license is available in the META-INF folder in all distributions of + * Syslog4j and in the base directory of the "doc" ZIP. + *

+ * + * @author Manish Motwani + * @version $Id: StructuredSyslogMessage.java,v 1.5 2010/09/11 16:49:24 cvs Exp $ + */ +public class StructuredSyslogMessage extends AbstractSyslogMessage implements StructuredSyslogMessageIF { + private static final long serialVersionUID = 3669887659567965965L; + + private String messageId; + private Map structuredData; + private String message; + + private StructuredSyslogMessage() { + this.messageId = null; + this.message = null; + this.structuredData = null; + } + + /** + * Constructs the {@link StructuredSyslogMessage} using MSGID, + * STRUCTURED-DATA and MSG fields, as described in: + * + *

+ * http://tools.ietf.org/html/draft-ietf-syslog-protocol-23#section-6 + *

+ * + * The Map must be a String -> (Map of String -> String), which encompasses + * the STRUCTURED-DATA field described in above document. + * + * @param messageId + * @param structuredData + * @param message + */ + public StructuredSyslogMessage(final String messageId, + final Map structuredData, final String message) { + super(); + this.messageId = messageId; + this.structuredData = structuredData; + this.message = message; + + ensureCorrectMapType(); + } + + private void ensureCorrectMapType() { + if (!(getStructuredData() == null)) { + Set sdEntrySet = getStructuredData().entrySet(); + for (Iterator it = sdEntrySet.iterator(); it.hasNext();) { + Map.Entry sdEntry = (Map.Entry) it.next(); + if (!(sdEntry.getKey() instanceof String)) { + throw new IllegalArgumentException( + "Structured data map must be a map of String -> (Map of String,String)"); + } + if (!(sdEntry.getValue() instanceof Map)) { + throw new IllegalArgumentException( + "Structured data map must be a map of String -> (Map of String,String)"); + } + + Set entrySet = ((Map) sdEntry.getValue()).entrySet(); + for (Iterator it2 = entrySet.iterator(); it2.hasNext();) { + Map.Entry entry = (Map.Entry) it2.next(); + + if (!(entry.getKey() instanceof String)) { + throw new IllegalArgumentException( + "Structured data map must be a map of String -> (Map of String,String)"); + } + if (!(entry.getValue() instanceof String)) { + throw new IllegalArgumentException( + "Structured data map must be a map of String -> (Map of String,String)"); + } + } + } + + } + } + + /** + * Parses and loads a {@link StructuredSyslogMessage} from string. + * + * @param syslogMessageStr + * @return Returns an instance of StructuredSyslogMessage. + */ + public static StructuredSyslogMessage fromString( + final String syslogMessageStr) { + final StructuredSyslogMessage syslogMessage = new StructuredSyslogMessage(); + syslogMessage.deserialize(syslogMessageStr); + return syslogMessage; + } + + private void deserialize(final String stringMessage) { + // Check correct format + if (stringMessage.indexOf('[') <= 0) + throw new IllegalArgumentException("Invalid Syslog string format: " + + stringMessage); + + // Divide the string in 2 sections + final String syslogHeader = stringMessage.substring(0, stringMessage + .indexOf('[')); + String structuredDataString = stringMessage.substring(stringMessage + .indexOf('['), stringMessage.lastIndexOf(']') + 1); + + if ((stringMessage.lastIndexOf(']') + 2) <= stringMessage.length()) + this.message = stringMessage.substring(stringMessage.lastIndexOf(']') + 2); + + else { + this.message = ""; + } + + // Split into tokens + final String[] tokens = syslogHeader.split(" "); + + // Check number of tokens must be 1 -- rest of the header should already + // be stripped + if (tokens.length != 1) { + throw new IllegalArgumentException("Invalid Syslog string format: " + + stringMessage); + } + + this.messageId = SyslogConstants.STRUCTURED_DATA_NILVALUE.equals(tokens[0]) ? null + : tokens[0]; + + this.structuredData = new HashMap(); + if (!SyslogConstants.STRUCTURED_DATA_EMPTY_VALUE.equals(structuredDataString)) { + while (!"".equals(structuredDataString)) { + if (!structuredDataString.startsWith("[") + || structuredDataString.indexOf(']') == -1) { + throw new IllegalArgumentException( + "Invalid structured data format in Syslog message: " + + stringMessage); + } + + final String structuredDataIteration = structuredDataString + .substring(1, structuredDataString.indexOf(']')); + + final Map iterMap = new HashMap(); + + final String[] params = structuredDataIteration.split(" "); + + for (int i = 1; i < params.length; i++) { + final String[] paramIter = params[i].split("="); + if (paramIter.length != 2) { + throw new IllegalArgumentException( + "Invalid structured data format in Syslog message: " + + stringMessage); + } + + if (!paramIter[1].startsWith("\"") + || !paramIter[1].endsWith("\"")) { + throw new IllegalArgumentException( + "Invalid structured data format in Syslog message: " + + stringMessage); + } + + iterMap.put(paramIter[0], paramIter[1].substring(1, + paramIter[1].length() - 1)); + } + + this.structuredData.put(params[0], iterMap); + + if (structuredDataString.indexOf(']') != structuredDataString + .lastIndexOf(']')) { + structuredDataString = structuredDataString + .substring(structuredDataString.indexOf(']') + 1); + } else { + structuredDataString = ""; + } + } + } + } + + /** + * Returns the MSGID field of the structured message format, as described + * in: + * + *

+ * http://tools.ietf.org/html/draft-ietf-syslog-protocol-23#section-6 + *

+ * + * @return Returns the MSG ID field. + */ + public String getMessageId() { + return this.messageId; + } + + /** + * Returns the structured data map. The Map is a String -> (Map of String -> + * String), which encompasses the STRUCTURED-DATA field, as described in: + * + *

+ * http://tools.ietf.org/html/draft-ietf-syslog-protocol-23#section-6 + *

+ * + * @return Returns a Map object containing structured data. + */ + public Map getStructuredData() { + return this.structuredData; + } + + /** + * Returns the MSG field of the structured message format, as described in: + * + *

+ * http://tools.ietf.org/html/draft-ietf-syslog-protocol-23#section-6 + *

+ * + * @return Returns the MSG field. + */ + public String getMessage() { + return this.message; + } + + /* + * (non-Javadoc) + * + * @seeorg.productivity.java.syslog4j.impl.message.AbstractSyslogMessage# + * createMessage() + */ + public String createMessage() { + return serialize(); + } + + private String serialize() { + if (!StructuredSyslogMessage.checkIsPrintable(getMessageId())) + throw new IllegalArgumentException("Invalid message id: " + + getMessageId()); + + final StringBuffer sb = new StringBuffer(); + + sb.append(StructuredSyslogMessage.nilProtect(getMessageId())); + sb.append(' '); + + if (getStructuredData() == null || getStructuredData().size() == 0) { + // This is not desired, but rsyslogd does not store version 1 syslog + // message correctly if + // there is no + // structured data present + sb.append(SyslogConstants.STRUCTURED_DATA_EMPTY_VALUE); + } else { + Set sdEntrySet = getStructuredData().entrySet(); + for (Iterator it = sdEntrySet.iterator(); it.hasNext();) { + final Map.Entry sdElement = (Map.Entry) it.next(); + final String sdId = (String) sdElement.getKey(); + + if (sdId == null || sdId.length() == 0 + || !StructuredSyslogMessage.checkIsPrintable(sdId)) { + throw new IllegalArgumentException( + "Illegal structured data id: " + sdId); + } + + sb.append('[').append(sdId); + + final Map sdParams = (Map) sdElement.getValue(); + + if (sdParams != null) { + Set entrySet = sdParams.entrySet(); + for (Iterator it2 = entrySet.iterator(); it2.hasNext();) { + Map.Entry entry = (Map.Entry) it2.next(); + final String paramName = (String) entry.getKey(); + final String paramValue = (String) entry.getValue(); + + if (paramName == null + || paramName.length() == 0 + || !StructuredSyslogMessage + .checkIsPrintable(paramName)) + throw new IllegalArgumentException( + "Illegal structured data parameter name: " + + paramName); + + if (paramValue == null) + throw new IllegalArgumentException( + "Null structured data parameter value for parameter name: " + + paramName); + + sb.append(' '); + sb.append(paramName); + sb.append('=').append('"'); + StructuredSyslogMessage.sdEscape(sb, paramValue); + sb.append('"'); + } + } + + sb.append(']'); + } + } + + if (getMessage() != null && getMessage().length() != 0) { + sb.append(' '); + sb.append(StructuredSyslogMessage.nilProtect(getMessage())); + } + + return sb.toString(); + + } + + public static void sdEscape(final StringBuffer sb, final String value) { + for (int i = 0; i < value.length(); i++) { + final char c = value.charAt(i); + + if (c == '"' || c == '\\' || c == ']') { + sb.append('\\'); + } + + sb.append(c); + } + } + + public static boolean checkIsPrintable(final String value) { + if (value == null) + return true; + + for (int i = 0; i < value.length(); i++) { + final char c = value.charAt(i); + + if (c < 33 || c > 126) + return false; + } + + return true; + } + + public static String nilProtect(final String value) { + if (value == null || value.trim().length() == 0) { + return SyslogConstants.STRUCTURED_DATA_NILVALUE; + } + + return value; + } + + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((message == null) ? 0 : message.hashCode()); + result = prime * result + + ((messageId == null) ? 0 : messageId.hashCode()); + result = prime * result + + ((structuredData == null) ? 0 : structuredData.hashCode()); + return result; + } + + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + + StructuredSyslogMessage other = (StructuredSyslogMessage) obj; + + if (message == null) { + if (other.message != null) return false; + + } else if (!message.equals(other.message)) return false; + + if (messageId == null) { + if (other.messageId != null) return false; + + } else if (!messageId.equals(other.messageId)) return false; + + if (structuredData == null) { + if (other.structuredData != null) return false; + + } else if (!structuredData.equals(other.structuredData)) return false; + + return true; + } + + public String toString() { + return serialize(); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessageIF.java b/src/main/java/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessageIF.java new file mode 100644 index 0000000..480120c --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessageIF.java @@ -0,0 +1,18 @@ +package org.productivity.java.syslog4j.impl.message.structured; + +import org.productivity.java.syslog4j.SyslogMessageIF; + +/** +* StructuredSyslogMessageIF is a "marker" interface to identify structured +* SyslogMessageIF implementations. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: StructuredSyslogMessageIF.java,v 1.1 2009/07/22 15:54:23 cvs Exp $ +*/ +public interface StructuredSyslogMessageIF extends SyslogMessageIF { + // +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/multiple/MultipleSyslog.java b/src/main/java/org/productivity/java/syslog4j/impl/multiple/MultipleSyslog.java new file mode 100644 index 0000000..70e632f --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/multiple/MultipleSyslog.java @@ -0,0 +1,174 @@ +package org.productivity.java.syslog4j.impl.multiple; + +import org.productivity.java.syslog4j.Syslog; +import org.productivity.java.syslog4j.SyslogConfigIF; +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogIF; +import org.productivity.java.syslog4j.SyslogMessageIF; +import org.productivity.java.syslog4j.SyslogMessageProcessorIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; + +/** +* MultipleSyslog is an aggregator Syslog implementation for allowing a single +* Syslog call to send to multiple Syslog implementations. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: MultipleSyslog.java,v 1.10 2010/02/11 05:00:55 cvs Exp $ +*/ +public class MultipleSyslog implements SyslogIF { + private static final long serialVersionUID = 587308197526365108L; + + protected String syslogProtocol = null; + protected MultipleSyslogConfig multipleSyslogConfig = null; + + public void initialize(String protocol, SyslogConfigIF config) throws SyslogRuntimeException { + this.syslogProtocol = protocol; + + try { + this.multipleSyslogConfig = (MultipleSyslogConfig) config; + + } catch (ClassCastException cce) { + throw new SyslogRuntimeException("config must be of type MultipleSyslogConfig"); + } + } + + public SyslogConfigIF getConfig() { + return this.multipleSyslogConfig; + } + + public void debug(String message) { + log(SyslogConstants.LEVEL_DEBUG,message); + } + + public void debug(SyslogMessageIF message) { + log(SyslogConstants.LEVEL_DEBUG,message); + } + + public void critical(String message) { + log(SyslogConstants.LEVEL_CRITICAL,message); + } + + public void critical(SyslogMessageIF message) { + log(SyslogConstants.LEVEL_CRITICAL,message); + } + + public void error(String message) { + log(SyslogConstants.LEVEL_ERROR,message); + } + + public void error(SyslogMessageIF message) { + log(SyslogConstants.LEVEL_ERROR,message); + } + + public void alert(String message) { + log(SyslogConstants.LEVEL_ALERT,message); + } + + public void alert(SyslogMessageIF message) { + log(SyslogConstants.LEVEL_ALERT,message); + } + + public void notice(String message) { + log(SyslogConstants.LEVEL_NOTICE,message); + } + + public void notice(SyslogMessageIF message) { + log(SyslogConstants.LEVEL_NOTICE,message); + } + + public void emergency(String message) { + log(SyslogConstants.LEVEL_EMERGENCY,message); + } + + public void emergency(SyslogMessageIF message) { + log(SyslogConstants.LEVEL_EMERGENCY,message); + } + + public void info(String message) { + log(SyslogConstants.LEVEL_INFO,message); + } + + public void info(SyslogMessageIF message) { + log(SyslogConstants.LEVEL_INFO,message); + } + + public void warn(String message) { + log(SyslogConstants.LEVEL_WARN,message); + } + + public void warn(SyslogMessageIF message) { + log(SyslogConstants.LEVEL_WARN,message); + } + + public void log(int level, String message) { + for(int i=0; iSyslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: MultipleSyslogConfig.java,v 1.8 2010/11/28 04:15:18 cvs Exp $ +*/ +public class MultipleSyslogConfig implements SyslogConfigIF { + private static final long serialVersionUID = 753704522364959612L; + + protected List syslogProtocols = null; + + public MultipleSyslogConfig() { + this.syslogProtocols = new ArrayList(); + } + + public MultipleSyslogConfig(List protocols) { + if (protocols != null) { + this.syslogProtocols = protocols; + + } else { + this.syslogProtocols = new ArrayList(); + } + } + + public MultipleSyslogConfig(String[] protocols) { + if (protocols != null) { + this.syslogProtocols = new ArrayList(protocols.length); + + for(int i=0; iSyslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractNetSyslog.java,v 1.7 2009/01/24 22:00:18 cvs Exp $ +*/ +public abstract class AbstractNetSyslog extends AbstractSyslog { + private static final long serialVersionUID = -3250858945515853967L; + + protected static final Object cachedHostAddressSyncObject = new Object(); + + protected InetAddress cachedHostAddress = null; + + protected AbstractNetSyslogConfigIF netSyslogConfig = null; + + protected void initialize() throws SyslogRuntimeException { + try { + this.netSyslogConfig = (AbstractNetSyslogConfigIF) this.syslogConfig; + + } catch (ClassCastException cce) { + throw new SyslogRuntimeException("config must implement interface AbstractNetSyslogConfigIF"); + } + } + + /** + * @return Returns an object of InetAddress of the local host, using caching if so directed. + */ + public InetAddress getHostAddress() { + InetAddress hostAddress = null; + + if (this.netSyslogConfig.isCacheHostAddress()) { + if (this.cachedHostAddress == null) { + synchronized(cachedHostAddressSyncObject) { + if (this.cachedHostAddress == null) { + this.cachedHostAddress = SyslogUtility.getInetAddress(this.syslogConfig.getHost()); + } + } + } + + hostAddress = this.cachedHostAddress; + + } else { + hostAddress = SyslogUtility.getInetAddress(this.syslogConfig.getHost()); + } + + return hostAddress; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/AbstractNetSyslogConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/net/AbstractNetSyslogConfig.java new file mode 100644 index 0000000..c829b70 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/AbstractNetSyslogConfig.java @@ -0,0 +1,85 @@ +package org.productivity.java.syslog4j.impl.net; + +import org.productivity.java.syslog4j.impl.AbstractSyslogConfig; + +/** +* AbstractNetSyslogConfig is an abstract extension of AbstractSyslogConfig +* that provides configuration support for network-based syslog clients. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractNetSyslogConfig.java,v 1.12 2010/10/25 03:50:25 cvs Exp $ +*/ +public abstract class AbstractNetSyslogConfig extends AbstractSyslogConfig implements AbstractNetSyslogConfigIF { + private static final long serialVersionUID = 7240133962159244924L; + + protected String host = SYSLOG_HOST_DEFAULT; + protected int port = SYSLOG_PORT_DEFAULT; + + protected boolean cacheHostAddress = CACHE_HOST_ADDRESS_DEFAULT; + + protected int maxQueueSize = MAX_QUEUE_SIZE_DEFAULT; + + public AbstractNetSyslogConfig() { + // + } + + public AbstractNetSyslogConfig(int facility) { + this.facility = facility; + } + + public AbstractNetSyslogConfig(int facility, String host) { + this.facility = facility; + this.host = host; + } + + public AbstractNetSyslogConfig(String host) { + this.host = host; + } + + public AbstractNetSyslogConfig(int facility, String host, int port) { + this.facility = facility; + this.host = host; + this.port = port; + } + + public AbstractNetSyslogConfig(String host, int port) { + this.host = host; + this.port = port; + } + + public boolean isCacheHostAddress() { + return this.cacheHostAddress; + } + + public void setCacheHostAddress(boolean cacheHostAddress) { + this.cacheHostAddress = cacheHostAddress; + } + + public String getHost() { + return this.host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return this.port; + } + + public void setPort(int port) { + this.port = port; + } + + public int getMaxQueueSize() { + return maxQueueSize; + } + + public void setMaxQueueSize(int maxQueueSize) { + this.maxQueueSize = maxQueueSize; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/AbstractNetSyslogConfigIF.java b/src/main/java/org/productivity/java/syslog4j/impl/net/AbstractNetSyslogConfigIF.java new file mode 100644 index 0000000..17d7940 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/AbstractNetSyslogConfigIF.java @@ -0,0 +1,19 @@ +package org.productivity.java.syslog4j.impl.net; + +import org.productivity.java.syslog4j.impl.AbstractSyslogConfigIF; + +/** +* AbstractNetSyslogConfigIF is a configuration interface supporting network-based +* Syslog implementations. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractNetSyslogConfigIF.java,v 1.4 2009/06/06 19:11:02 cvs Exp $ +*/ +public interface AbstractNetSyslogConfigIF extends AbstractSyslogConfigIF { + public boolean isCacheHostAddress(); + public void setCacheHostAddress(boolean cacheHostAddress); +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslog.java b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslog.java new file mode 100644 index 0000000..9d3e949 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslog.java @@ -0,0 +1,91 @@ +package org.productivity.java.syslog4j.impl.net.tcp; + +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.AbstractSyslogWriter; +import org.productivity.java.syslog4j.impl.net.AbstractNetSyslog; + +/** +* TCPNetSyslog is an extension of AbstractSyslog that provides support for +* TCP/IP-based syslog clients. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: TCPNetSyslog.java,v 1.21 2010/11/28 04:43:31 cvs Exp $ +*/ +public class TCPNetSyslog extends AbstractNetSyslog { + private static final long serialVersionUID = -2157528355215068721L; + + protected TCPNetSyslogWriter writer = null; + + protected TCPNetSyslogConfigIF tcpNetSyslogConfig = null; + + public void initialize() throws SyslogRuntimeException { + super.initialize(); + + try { + this.tcpNetSyslogConfig = (TCPNetSyslogConfigIF) this.syslogConfig; + + } catch (ClassCastException cce) { + throw new SyslogRuntimeException("config must implement interface TCPNetSyslogConfigIF"); + } + } + + public AbstractSyslogWriter getWriter() { + return getWriter(true); + } + + public synchronized AbstractSyslogWriter getWriter(boolean create) { + if (this.writer != null || !create) { + return this.writer; + } + + this.writer = (TCPNetSyslogWriter) createWriter(); + + if (this.tcpNetSyslogConfig.isThreaded()) { + createWriterThread(this.writer); + } + + return this.writer; + } + + protected void write(int level, byte[] message) throws SyslogRuntimeException { + AbstractSyslogWriter syslogWriter = getWriter(); + + try { + if (syslogWriter.hasThread()) { + syslogWriter.queue(level,message); + + } else { + synchronized(syslogWriter) { + syslogWriter.write(message); + } + } + + } finally { + returnWriter(syslogWriter); + } + } + + public void flush() throws SyslogRuntimeException { + AbstractSyslogWriter syslogWriter = getWriter(false); + + if (syslogWriter != null) { + syslogWriter.flush(); + } + } + + public void shutdown() throws SyslogRuntimeException { + AbstractSyslogWriter syslogWriter = getWriter(false); + + if (syslogWriter != null) { + syslogWriter.shutdown(); + } + } + + public void returnWriter(AbstractSyslogWriter syslogWriter) { + // + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogConfig.java new file mode 100644 index 0000000..49d8436 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogConfig.java @@ -0,0 +1,156 @@ +package org.productivity.java.syslog4j.impl.net.tcp; + +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.impl.net.AbstractNetSyslogConfig; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* TCPNetSyslogConfig is an extension of AbstractNetSyslogConfig that provides +* configuration support for TCP/IP-based syslog clients. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: TCPNetSyslogConfig.java,v 1.18 2010/10/29 03:14:12 cvs Exp $ +*/ +public class TCPNetSyslogConfig extends AbstractNetSyslogConfig implements TCPNetSyslogConfigIF { + private static final long serialVersionUID = 9023152050686365460L; + + public static byte[] SYSTEM_DELIMITER_SEQUENCE = null; + + static { + String delimiterSequence = System.getProperty("line.separator"); + + SYSTEM_DELIMITER_SEQUENCE = delimiterSequence.getBytes(); + + if (SYSTEM_DELIMITER_SEQUENCE == null || SYSTEM_DELIMITER_SEQUENCE.length < 1) { + SYSTEM_DELIMITER_SEQUENCE = SyslogConstants.TCP_DELIMITER_SEQUENCE_DEFAULT; + } + } + + protected byte[] delimiterSequence = SYSTEM_DELIMITER_SEQUENCE; + + protected boolean persistentConnection = TCP_PERSISTENT_CONNECTION_DEFAULT; + + protected boolean soLinger = TCP_SO_LINGER_DEFAULT; + protected int soLingerSeconds = TCP_SO_LINGER_SECONDS_DEFAULT; + + protected boolean keepAlive = TCP_KEEP_ALIVE_DEFAULT; + + protected boolean reuseAddress = TCP_REUSE_ADDRESS_DEFAULT; + + protected boolean setBufferSize = TCP_SET_BUFFER_SIZE_DEFAULT; + + protected int freshConnectionInterval = TCP_FRESH_CONNECTION_INTERVAL_DEFAULT; + + public TCPNetSyslogConfig() { + initialize(); + } + + protected void initialize() { + // + } + + public TCPNetSyslogConfig(int facility, String host, int port) { + super(facility, host, port); + initialize(); + } + + public TCPNetSyslogConfig(int facility, String host) { + super(facility, host); + initialize(); + } + + public TCPNetSyslogConfig(int facility) { + super(facility); + initialize(); + } + + public TCPNetSyslogConfig(String host, int port) { + super(host, port); + initialize(); + } + + public TCPNetSyslogConfig(String host) { + super(host); + initialize(); + } + + public Class getSyslogClass() { + return TCPNetSyslog.class; + } + + public byte[] getDelimiterSequence() { + return this.delimiterSequence; + } + + public void setDelimiterSequence(byte[] delimiterSequence) { + this.delimiterSequence = delimiterSequence; + } + + public void setDelimiterSequence(String delimiterSequence) { + this.delimiterSequence = SyslogUtility.getBytes(this,delimiterSequence); + } + + public boolean isPersistentConnection() { + return this.persistentConnection; + } + + public void setPersistentConnection(boolean persistentConnection) { + this.persistentConnection = persistentConnection; + } + + public boolean isSoLinger() { + return this.soLinger; + } + + public void setSoLinger(boolean soLinger) { + this.soLinger = soLinger; + } + + public int getSoLingerSeconds() { + return this.soLingerSeconds; + } + + public void setSoLingerSeconds(int soLingerSeconds) { + this.soLingerSeconds = soLingerSeconds; + } + + public boolean isKeepAlive() { + return this.keepAlive; + } + + public void setKeepAlive(boolean keepAlive) { + this.keepAlive = keepAlive; + } + + public boolean isReuseAddress() { + return this.reuseAddress; + } + + public void setReuseAddress(boolean reuseAddress) { + this.reuseAddress = reuseAddress; + } + + public boolean isSetBufferSize() { + return this.setBufferSize; + } + + public void setSetBufferSize(boolean setBufferSize) { + this.setBufferSize = setBufferSize; + } + + public int getFreshConnectionInterval() { + return freshConnectionInterval; + } + + public void setFreshConnectionInterval(int freshConnectionInterval) { + this.freshConnectionInterval = freshConnectionInterval; + } + + public Class getSyslogWriterClass() { + return TCPNetSyslogWriter.class; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogConfigIF.java b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogConfigIF.java new file mode 100644 index 0000000..82318ad --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogConfigIF.java @@ -0,0 +1,40 @@ +package org.productivity.java.syslog4j.impl.net.tcp; + +import org.productivity.java.syslog4j.impl.net.AbstractNetSyslogConfigIF; + +/** +* TCPNetSyslogConfigIF is a configuration interface supporting TCP/IP-based +* Syslog implementations. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: TCPNetSyslogConfigIF.java,v 1.6 2010/10/29 03:14:12 cvs Exp $ +*/ +public interface TCPNetSyslogConfigIF extends AbstractNetSyslogConfigIF { + public byte[] getDelimiterSequence(); + public void setDelimiterSequence(byte[] delimiterSequence); + + public boolean isPersistentConnection(); + public void setPersistentConnection(boolean persistentConnection); + + public boolean isSoLinger(); + public void setSoLinger(boolean soLinger); + + public int getSoLingerSeconds(); + public void setSoLingerSeconds(int soLingerSeconds); + + public boolean isKeepAlive(); + public void setKeepAlive(boolean keepAlive); + + public boolean isReuseAddress(); + public void setReuseAddress(boolean reuseAddress); + + public boolean isSetBufferSize(); + public void setSetBufferSize(boolean setBufferSize); + + public int getFreshConnectionInterval(); + public void setFreshConnectionInterval(int interval); +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogWriter.java b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogWriter.java new file mode 100644 index 0000000..3e178af --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogWriter.java @@ -0,0 +1,226 @@ +package org.productivity.java.syslog4j.impl.net.tcp; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; + +import javax.net.SocketFactory; + +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.AbstractSyslog; +import org.productivity.java.syslog4j.impl.AbstractSyslogWriter; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* TCPNetSyslogWriter is an implementation of Runnable that supports sending +* TCP-based messages within a separate Thread. +* +*

When used in "threaded" mode (see TCPNetSyslogConfig for the option), +* a queuing mechanism is used (via LinkedList).

+* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: TCPNetSyslogWriter.java,v 1.20 2010/11/28 01:38:08 cvs Exp $ +*/ +public class TCPNetSyslogWriter extends AbstractSyslogWriter { + private static final long serialVersionUID = -6388813866108482855L; + + protected TCPNetSyslog tcpNetSyslog = null; + + protected Socket socket = null; + + protected TCPNetSyslogConfigIF tcpNetSyslogConfig = null; + + protected long lastSocketCreationTimeMs = 0; + + public TCPNetSyslogWriter() { + // + } + + public void initialize(AbstractSyslog abstractSyslog) { + super.initialize(abstractSyslog); + + this.tcpNetSyslog = (TCPNetSyslog) abstractSyslog; + + this.tcpNetSyslogConfig = (TCPNetSyslogConfigIF) this.tcpNetSyslog.getConfig(); + } + + protected SocketFactory obtainSocketFactory() { + return SocketFactory.getDefault(); + } + + protected Socket createSocket(InetAddress hostAddress, int port, boolean keepalive) throws IOException { + SocketFactory socketFactory = obtainSocketFactory(); + + Socket newSocket = socketFactory.createSocket(hostAddress,port); + + if (this.tcpNetSyslogConfig.isSoLinger()) { + newSocket.setSoLinger(true,this.tcpNetSyslogConfig.getSoLingerSeconds()); + } + + if (this.tcpNetSyslogConfig.isKeepAlive()) { + newSocket.setKeepAlive(keepalive); + } + + if (this.tcpNetSyslogConfig.isReuseAddress()) { + newSocket.setReuseAddress(true); + } + + return newSocket; + } + + protected Socket getSocket() throws SyslogRuntimeException { + if (this.socket != null && this.socket.isConnected()) { + int freshConnectionInterval = this.tcpNetSyslogConfig.getFreshConnectionInterval(); + + if (freshConnectionInterval > 0) { + long currentTimeMs = System.currentTimeMillis(); + + if ((currentTimeMs - lastSocketCreationTimeMs) >= freshConnectionInterval) { + closeSocket(this.socket); + } + + } else { + return this.socket; + } + } + + if (this.socket == null) { + lastSocketCreationTimeMs = 0; + + try { + InetAddress hostAddress = this.tcpNetSyslog.getHostAddress(); + + this.socket = createSocket(hostAddress,this.syslog.getConfig().getPort(),this.tcpNetSyslogConfig.isPersistentConnection()); + lastSocketCreationTimeMs = System.currentTimeMillis(); + + } catch (IOException ioe) { + throw new SyslogRuntimeException(ioe); + } + } + + return this.socket; + } + + protected void closeSocket(Socket socketToClose) { + if (socketToClose == null) { + return; + } + + try { + socketToClose.close(); + + } catch (IOException ioe) { + if (!"Socket is closed".equalsIgnoreCase(ioe.getMessage())) { + throw new SyslogRuntimeException(ioe); + } + + } finally { + if (socketToClose == this.socket) { + this.socket = null; + } + } + } + + public void write(byte[] message) throws SyslogRuntimeException { + Socket currentSocket = null; + + int attempts = 0; + while(attempts != -1 && attempts < (this.tcpNetSyslogConfig.getWriteRetries() + 1)) { + try { + currentSocket = getSocket(); + + if (currentSocket == null) { + throw new SyslogRuntimeException("No socket available"); + } + + OutputStream os = currentSocket.getOutputStream(); + + if (this.tcpNetSyslogConfig.isSetBufferSize()) { + currentSocket.setSendBufferSize(message.length); + } + + os.write(message); + + byte[] delimiterSequence = this.tcpNetSyslogConfig.getDelimiterSequence(); + if (delimiterSequence != null && delimiterSequence.length > 0) { + os.write(delimiterSequence); + } + + this.syslog.setBackLogStatus(false); + + attempts = -1; + + if (!this.tcpNetSyslogConfig.isPersistentConnection()) { + closeSocket(currentSocket); + } + + } catch (IOException ioe) { + attempts++; + closeSocket(currentSocket); + + if (attempts >= (this.tcpNetSyslogConfig.getWriteRetries() + 1)) { + throw new SyslogRuntimeException(ioe); + } + } + } + } + + public synchronized void flush() throws SyslogRuntimeException { + if (this.socket == null) { + return; + } + + if (this.syslogConfig.isThreaded()) { + this.shutdown(); + this.syslog.createWriterThread(this); + + } else { + closeSocket(this.socket); + } + } + + public synchronized void shutdown() throws SyslogRuntimeException { + this.shutdown = true; + + if (this.syslogConfig.isThreaded()) { + long timeStart = System.currentTimeMillis(); + boolean done = false; + + while(!done) { + if (this.socket == null || this.socket.isClosed()) { + done = true; + + } else { + long now = System.currentTimeMillis(); + + if (now > (timeStart + this.tcpNetSyslogConfig.getMaxShutdownWait())) { + closeSocket(this.socket); + this.thread.interrupt(); + done = true; + } + + if (!done) { + SyslogUtility.sleep(SyslogConstants.SHUTDOWN_INTERVAL); + } + } + } + + } else { + if (this.socket == null || this.socket.isClosed()) { + return; + } + + closeSocket(this.socket); + } + } + + protected void runCompleted() { + closeSocket(this.socket); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslog.java b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslog.java new file mode 100644 index 0000000..c1f7884 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslog.java @@ -0,0 +1,76 @@ +package org.productivity.java.syslog4j.impl.net.tcp.pool; + +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.AbstractSyslogWriter; +import org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslog; +import org.productivity.java.syslog4j.impl.pool.AbstractSyslogPoolFactory; +import org.productivity.java.syslog4j.impl.pool.generic.GenericSyslogPoolFactory; + +/** +* PooledTCPNetSyslog is an extension of TCPNetSyslog which provides support +* for Apache Commons Pool. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: PooledTCPNetSyslog.java,v 1.5 2008/12/10 04:30:15 cvs Exp $ +*/ +public class PooledTCPNetSyslog extends TCPNetSyslog { + private static final long serialVersionUID = 4279960451141784200L; + + protected AbstractSyslogPoolFactory poolFactory = null; + + public void initialize() throws SyslogRuntimeException { + super.initialize(); + + this.poolFactory = createSyslogPoolFactory(); + + this.poolFactory.initialize(this); + } + + protected AbstractSyslogPoolFactory createSyslogPoolFactory() { + AbstractSyslogPoolFactory syslogPoolFactory = new GenericSyslogPoolFactory(); + + return syslogPoolFactory; + } + + public AbstractSyslogWriter getWriter() { + try { + AbstractSyslogWriter syslogWriter = this.poolFactory.borrowSyslogWriter(); + + return syslogWriter; + + } catch (Exception e) { + throw new SyslogRuntimeException(e); + } + } + + public void returnWriter(AbstractSyslogWriter syslogWriter) { + try { + this.poolFactory.returnSyslogWriter(syslogWriter); + + } catch (Exception e) { + throw new SyslogRuntimeException(e); + } + } + + public void flush() throws SyslogRuntimeException { + try { + this.poolFactory.clear(); + + } catch (Exception e) { + // + } + } + + public void shutdown() throws SyslogRuntimeException { + try { + this.poolFactory.close(); + + } catch (Exception e) { + // + } + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslogConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslogConfig.java new file mode 100644 index 0000000..91a1ba4 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslogConfig.java @@ -0,0 +1,172 @@ +package org.productivity.java.syslog4j.impl.net.tcp.pool; + +import org.apache.commons.pool.impl.GenericObjectPool; +import org.productivity.java.syslog4j.SyslogPoolConfigIF; +import org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslogConfig; + +/** +* NetSyslogPoolFactory is an implementation of SyslogPoolConfigIF +* which provides configuration support for the Apache Commons Pool. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: PooledTCPNetSyslogConfig.java,v 1.3 2008/11/26 15:01:47 cvs Exp $ +*/ +public class PooledTCPNetSyslogConfig extends TCPNetSyslogConfig implements SyslogPoolConfigIF { + private static final long serialVersionUID = 2283355983363422888L; + + protected int maxActive = SYSLOG_POOL_CONFIG_MAX_ACTIVE_DEFAULT; + protected int maxIdle = SYSLOG_POOL_CONFIG_MAX_IDLE_DEFAULT; + protected long maxWait = SYSLOG_POOL_CONFIG_MAX_WAIT_DEFAULT; + protected long minEvictableIdleTimeMillis = SYSLOG_POOL_CONFIG_MIN_EVICTABLE_IDLE_TIME_MILLIS_DEFAULT; + protected int minIdle = SYSLOG_POOL_CONFIG_MIN_IDLE_DEFAULT; + protected int numTestsPerEvictionRun = SYSLOG_POOL_CONFIG_NUM_TESTS_PER_EVICTION_RUN_DEFAULT; + protected long softMinEvictableIdleTimeMillis = SYSLOG_POOL_CONFIG_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS_DEFAULT; + protected long timeBetweenEvictionRunsMillis = SYSLOG_POOL_CONFIG_TIME_BETWEEN_EVICTION_RUNS_MILLIS_DEFAULT; + protected byte whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_BLOCK; + protected boolean testOnBorrow = SYSLOG_POOL_CONFIG_TEST_ON_BORROW_DEFAULT; + protected boolean testOnReturn = SYSLOG_POOL_CONFIG_TEST_ON_RETURN_DEFAULT; + protected boolean testWhileIdle = SYSLOG_POOL_CONFIG_TEST_WHILE_IDLE_DEFAULT; + + public PooledTCPNetSyslogConfig() { + // + } + + public PooledTCPNetSyslogConfig(int facility, String host, int port) { + super(facility, host, port); + } + + public PooledTCPNetSyslogConfig(int facility, String host) { + super(facility, host); + } + + public PooledTCPNetSyslogConfig(int facility) { + super(facility); + } + + public PooledTCPNetSyslogConfig(String host, int port) { + super(host, port); + } + + public PooledTCPNetSyslogConfig(String host) { + super(host); + } + + protected void configureThreadedValues(int value) { + if (isThreaded()) { + this.minIdle = value; + this.maxIdle = value; + this.maxActive = value; + } + } + + public int getMaxActive() { + return this.maxActive; + } + + public void setMaxActive(int maxActive) { + configureThreadedValues(maxActive); + + this.maxActive = maxActive; + } + + public int getMaxIdle() { + return this.maxIdle; + } + + public void setMaxIdle(int maxIdle) { + configureThreadedValues(maxIdle); + + this.maxIdle = maxIdle; + } + + public long getMaxWait() { + return this.maxWait; + } + + public void setMaxWait(long maxWait) { + this.maxWait = maxWait; + } + + public long getMinEvictableIdleTimeMillis() { + return this.minEvictableIdleTimeMillis; + } + + public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { + this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; + } + + public int getMinIdle() { + return this.minIdle; + } + + public void setMinIdle(int minIdle) { + configureThreadedValues(minIdle); + + this.minIdle = minIdle; + } + + public int getNumTestsPerEvictionRun() { + return this.numTestsPerEvictionRun; + } + + public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { + this.numTestsPerEvictionRun = numTestsPerEvictionRun; + } + + public long getSoftMinEvictableIdleTimeMillis() { + return this.softMinEvictableIdleTimeMillis; + } + + public void setSoftMinEvictableIdleTimeMillis( + long softMinEvictableIdleTimeMillis) { + this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis; + } + + public long getTimeBetweenEvictionRunsMillis() { + return this.timeBetweenEvictionRunsMillis; + } + + public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { + this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; + } + + public byte getWhenExhaustedAction() { + return this.whenExhaustedAction; + } + + public void setWhenExhaustedAction(byte whenExhaustedAction) { + this.whenExhaustedAction = whenExhaustedAction; + } + + public boolean isTestOnBorrow() { + return this.testOnBorrow; + } + + public void setTestOnBorrow(boolean testOnBorrow) { + this.testOnBorrow = testOnBorrow; + } + + public boolean isTestOnReturn() { + return this.testOnReturn; + } + + public void setTestOnReturn(boolean testOnReturn) { + this.testOnReturn = testOnReturn; + } + + public boolean isTestWhileIdle() { + return this.testWhileIdle; + } + + public void setTestWhileIdle(boolean testWhileIdle) { + this.testWhileIdle = testWhileIdle; + } + + public Class getSyslogClass() { + return PooledTCPNetSyslog.class; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslog.java b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslog.java new file mode 100644 index 0000000..bb52c92 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslog.java @@ -0,0 +1,49 @@ +package org.productivity.java.syslog4j.impl.net.tcp.ssl; + +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslog; + +/** +* SSLTCPNetSyslog is an extension of AbstractSyslog that provides support for +* TCP/IP-based (over SSL/TLS) syslog clients. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SSLTCPNetSyslog.java,v 1.1 2009/03/29 17:38:58 cvs Exp $ +*/ +public class SSLTCPNetSyslog extends TCPNetSyslog { + private static final long serialVersionUID = 2766654802524487317L; + + public void initialize() throws SyslogRuntimeException { + super.initialize(); + + SSLTCPNetSyslogConfigIF sslTcpNetSyslogConfig = (SSLTCPNetSyslogConfigIF) this.tcpNetSyslogConfig; + + String keyStore = sslTcpNetSyslogConfig.getKeyStore(); + + if (keyStore != null && !"".equals(keyStore.trim())) { + System.setProperty("javax.net.ssl.keyStore",keyStore); + } + + String keyStorePassword = sslTcpNetSyslogConfig.getKeyStorePassword(); + + if (keyStorePassword != null && !"".equals(keyStorePassword.trim())) { + System.setProperty("javax.net.ssl.keyStorePassword",keyStorePassword); + } + + String trustStore = sslTcpNetSyslogConfig.getTrustStore(); + + if (trustStore != null && !"".equals(trustStore.trim())) { + System.setProperty("javax.net.ssl.trustStore",trustStore); + } + + String trustStorePassword = sslTcpNetSyslogConfig.getTrustStorePassword(); + + if (trustStorePassword != null && !"".equals(trustStorePassword.trim())) { + System.setProperty("javax.net.ssl.trustStorePassword",trustStorePassword); + } + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogConfig.java new file mode 100644 index 0000000..d1cf7de --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogConfig.java @@ -0,0 +1,88 @@ +package org.productivity.java.syslog4j.impl.net.tcp.ssl; + +import org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslogConfig; + +/** +* SSLTCPNetSyslogConfig is an extension of TCPNetSyslogConfig that provides +* configuration support for TCP/IP-based (over SSL/TLS) syslog clients. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SSLTCPNetSyslogConfig.java,v 1.2 2009/03/29 17:38:58 cvs Exp $ +*/ +public class SSLTCPNetSyslogConfig extends TCPNetSyslogConfig implements SSLTCPNetSyslogConfigIF { + private static final long serialVersionUID = 5569086213824510834L; + + protected String keyStore = null; + protected String keyStorePassword = null; + + protected String trustStore = null; + protected String trustStorePassword = null; + + public SSLTCPNetSyslogConfig() { + // + } + + public SSLTCPNetSyslogConfig(int facility, String host, int port) { + super(facility, host, port); + } + + public SSLTCPNetSyslogConfig(int facility, String host) { + super(facility, host); + } + + public SSLTCPNetSyslogConfig(int facility) { + super(facility); + } + + public SSLTCPNetSyslogConfig(String host, int port) { + super(host, port); + } + + public SSLTCPNetSyslogConfig(String host) { + super(host); + } + + public String getKeyStore() { + return this.keyStore; + } + + public void setKeyStore(String keyStore) { + this.keyStore = keyStore; + } + + public String getKeyStorePassword() { + return this.keyStorePassword; + } + + public void setKeyStorePassword(String keyStorePassword) { + this.keyStorePassword = keyStorePassword; + } + + public String getTrustStore() { + return this.trustStore; + } + + public void setTrustStore(String trustStore) { + this.trustStore = trustStore; + } + + public String getTrustStorePassword() { + return this.trustStorePassword; + } + + public void setTrustStorePassword(String trustStorePassword) { + this.trustStorePassword = trustStorePassword; + } + + public Class getSyslogClass() { + return SSLTCPNetSyslog.class; + } + + public Class getSyslogWriterClass() { + return SSLTCPNetSyslogWriter.class; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogConfigIF.java b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogConfigIF.java new file mode 100644 index 0000000..967631a --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogConfigIF.java @@ -0,0 +1,28 @@ +package org.productivity.java.syslog4j.impl.net.tcp.ssl; + +import org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslogConfigIF; + +/** +* SSLTCPNetSyslogConfigIF is a configuration interface supporting TCP/IP-based +* (over SSL/TLS) Syslog implementations. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SSLTCPNetSyslogConfigIF.java,v 1.1 2009/03/29 17:38:58 cvs Exp $ +*/ +public interface SSLTCPNetSyslogConfigIF extends TCPNetSyslogConfigIF { + public String getKeyStore(); + public void setKeyStore(String keyStore); + + public String getKeyStorePassword(); + public void setKeyStorePassword(String keyStorePassword); + + public String getTrustStore(); + public void setTrustStore(String trustStore); + + public String getTrustStorePassword(); + public void setTrustStorePassword(String trustStorePassword); +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogWriter.java b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogWriter.java new file mode 100644 index 0000000..61a9de0 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogWriter.java @@ -0,0 +1,28 @@ +package org.productivity.java.syslog4j.impl.net.tcp.ssl; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLSocketFactory; + +import org.productivity.java.syslog4j.impl.net.tcp.TCPNetSyslogWriter; + +/** +* SSLTCPNetSyslogWriter is an implementation of Runnable that supports sending +* TCP/IP-based (over SSL/TLS) messages within a separate Thread. +* +*

When used in "threaded" mode (see TCPNetSyslogConfig for the option), +* a queuing mechanism is used (via LinkedList).

+* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SSLTCPNetSyslogWriter.java,v 1.4 2009/03/29 17:38:58 cvs Exp $ +*/ +public class SSLTCPNetSyslogWriter extends TCPNetSyslogWriter { + private static final long serialVersionUID = 8944446235285662244L; + + protected SocketFactory obtainSocketFactory() { + return SSLSocketFactory.getDefault(); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/pool/PooledSSLTCPNetSyslogConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/pool/PooledSSLTCPNetSyslogConfig.java new file mode 100644 index 0000000..fb3f3fe --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/tcp/ssl/pool/PooledSSLTCPNetSyslogConfig.java @@ -0,0 +1,91 @@ +package org.productivity.java.syslog4j.impl.net.tcp.ssl.pool; + +import org.productivity.java.syslog4j.impl.net.tcp.pool.PooledTCPNetSyslogConfig; +import org.productivity.java.syslog4j.impl.net.tcp.ssl.SSLTCPNetSyslog; +import org.productivity.java.syslog4j.impl.net.tcp.ssl.SSLTCPNetSyslogConfigIF; +import org.productivity.java.syslog4j.impl.net.tcp.ssl.SSLTCPNetSyslogWriter; + +/** +* PooledSSLTCPNetSyslogConfig is an extension of PooledTCPNetSyslogConfig +* which provides configuration support for the Apache Commons Pool. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: PooledSSLTCPNetSyslogConfig.java,v 1.2 2009/03/29 17:38:58 cvs Exp $ +*/ +public class PooledSSLTCPNetSyslogConfig extends PooledTCPNetSyslogConfig implements SSLTCPNetSyslogConfigIF { + private static final long serialVersionUID = 2092268298395023976L; + + protected String keyStore = null; + protected String keyStorePassword = null; + + protected String trustStore = null; + protected String trustStorePassword = null; + + public PooledSSLTCPNetSyslogConfig() { + super(); + } + + public PooledSSLTCPNetSyslogConfig(int facility, String host, int port) { + super(facility, host, port); + } + + public PooledSSLTCPNetSyslogConfig(int facility, String host) { + super(facility, host); + } + + public PooledSSLTCPNetSyslogConfig(int facility) { + super(facility); + } + + public PooledSSLTCPNetSyslogConfig(String host, int port) { + super(host, port); + } + + public PooledSSLTCPNetSyslogConfig(String host) { + super(host); + } + + public String getKeyStore() { + return this.keyStore; + } + + public void setKeyStore(String keyStore) { + this.keyStore = keyStore; + } + + public String getKeyStorePassword() { + return this.keyStorePassword; + } + + public void setKeyStorePassword(String keyStorePassword) { + this.keyStorePassword = keyStorePassword; + } + + public String getTrustStore() { + return this.trustStore; + } + + public void setTrustStore(String trustStore) { + this.trustStore = trustStore; + } + + public String getTrustStorePassword() { + return this.trustStorePassword; + } + + public void setTrustStorePassword(String trustStorePassword) { + this.trustStorePassword = trustStorePassword; + } + + public Class getSyslogClass() { + return SSLTCPNetSyslog.class; + } + + public Class getSyslogWriterClass() { + return SSLTCPNetSyslogWriter.class; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/udp/UDPNetSyslog.java b/src/main/java/org/productivity/java/syslog4j/impl/net/udp/UDPNetSyslog.java new file mode 100644 index 0000000..9b6f813 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/udp/UDPNetSyslog.java @@ -0,0 +1,104 @@ +package org.productivity.java.syslog4j.impl.net.udp; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; + +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.AbstractSyslogWriter; +import org.productivity.java.syslog4j.impl.net.AbstractNetSyslog; + +/** +* UDPNetSyslog is an extension of AbstractSyslog that provides support for +* UDP/IP-based syslog clients. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: UDPNetSyslog.java,v 1.18 2010/10/27 06:18:10 cvs Exp $ +*/ +public class UDPNetSyslog extends AbstractNetSyslog { + private static final long serialVersionUID = 5259485504549037999L; + + protected DatagramSocket socket = null; + + public void initialize() throws SyslogRuntimeException { + super.initialize(); + + createDatagramSocket(true); + } + + protected synchronized void createDatagramSocket(boolean initialize) { + try { + this.socket = new DatagramSocket(); + + } catch (SocketException se) { + if (initialize) { + if (this.syslogConfig.isThrowExceptionOnInitialize()) { + throw new SyslogRuntimeException(se); + } + + } else { + throw new SyslogRuntimeException(se); + } + } + + if (this.socket == null) { + throw new SyslogRuntimeException("Cannot seem to get a Datagram socket"); + } + } + + protected void write(int level, byte[] message) throws SyslogRuntimeException { + if (this.socket == null) { + createDatagramSocket(false); + } + + InetAddress hostAddress = getHostAddress(); + + DatagramPacket packet = new DatagramPacket( + message, + message.length, + hostAddress, + this.syslogConfig.getPort() + ); + + int attempts = 0; + + while(attempts != -1 && attempts < (this.netSyslogConfig.getWriteRetries() + 1)) { + try { + this.socket.send(packet); + attempts = -1; + + } catch (IOException ioe) { + if (attempts == (this.netSyslogConfig.getWriteRetries() + 1)) { + throw new SyslogRuntimeException(ioe); + } + } + } + } + + public void flush() throws SyslogRuntimeException { + shutdown(); + + createDatagramSocket(true); + } + + public void shutdown() throws SyslogRuntimeException { + if (this.socket != null) { + this.socket.close(); + this.socket = null; + } + } + + public AbstractSyslogWriter getWriter() { + return null; + } + + public void returnWriter(AbstractSyslogWriter syslogWriter) { + // + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/net/udp/UDPNetSyslogConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/net/udp/UDPNetSyslogConfig.java new file mode 100644 index 0000000..9ab98e4 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/net/udp/UDPNetSyslogConfig.java @@ -0,0 +1,46 @@ +package org.productivity.java.syslog4j.impl.net.udp; + +import org.productivity.java.syslog4j.impl.net.AbstractNetSyslogConfig; + +/** +* UDPNetSyslogConfig is an extension of AbstractNetSyslogConfig that provides +* configuration support for UDP/IP-based syslog clients. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: UDPNetSyslogConfig.java,v 1.6 2008/11/14 04:32:00 cvs Exp $ +*/ +public class UDPNetSyslogConfig extends AbstractNetSyslogConfig { + private static final long serialVersionUID = 4465067182562754345L; + + public UDPNetSyslogConfig() { + super(); + } + + public UDPNetSyslogConfig(int facility, String host, int port) { + super(facility,host,port); + } + + public UDPNetSyslogConfig(int facility, String host) { + super(facility,host); + } + + public UDPNetSyslogConfig(int facility) { + super(facility); + } + + public UDPNetSyslogConfig(String host, int port) { + super(host,port); + } + + public UDPNetSyslogConfig(String host) { + super(host); + } + + public Class getSyslogClass() { + return UDPNetSyslog.class; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/pool/AbstractSyslogPoolFactory.java b/src/main/java/org/productivity/java/syslog4j/impl/pool/AbstractSyslogPoolFactory.java new file mode 100644 index 0000000..14d3dfe --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/pool/AbstractSyslogPoolFactory.java @@ -0,0 +1,84 @@ +package org.productivity.java.syslog4j.impl.pool; + +import org.apache.commons.pool.BasePoolableObjectFactory; +import org.apache.commons.pool.ObjectPool; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.AbstractSyslog; +import org.productivity.java.syslog4j.impl.AbstractSyslogConfigIF; +import org.productivity.java.syslog4j.impl.AbstractSyslogWriter; + +/** +* AbstractSyslogPoolFactory is an abstract implementation of the Apache Commons Pool +* BasePoolableObjectFactory. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractSyslogPoolFactory.java,v 1.5 2008/12/10 04:15:11 cvs Exp $ +* @see org.productivity.java.syslog4j.impl.pool.generic.GenericSyslogPoolFactory +*/ +public abstract class AbstractSyslogPoolFactory extends BasePoolableObjectFactory { + private static final long serialVersionUID = -7441569603980981508L; + + protected AbstractSyslog syslog = null; + protected AbstractSyslogConfigIF syslogConfig = null; + + protected ObjectPool pool = null; + + public AbstractSyslogPoolFactory() { + // + } + + public void initialize(AbstractSyslog abstractSyslog) throws SyslogRuntimeException { + this.syslog = abstractSyslog; + + try { + this.syslogConfig = (AbstractSyslogConfigIF) this.syslog.getConfig(); + + } catch (ClassCastException cce) { + throw new SyslogRuntimeException("config must implement AbstractSyslogConfigIF"); + } + + this.pool = createPool(); + } + + public Object makeObject() throws Exception { + AbstractSyslogWriter syslogWriter = this.syslog.createWriter(); + + if (this.syslogConfig.isThreaded()) { + this.syslog.createWriterThread(syslogWriter); + } + + return syslogWriter; + } + + public void destroyObject(Object obj) throws Exception { + AbstractSyslogWriter writer = (AbstractSyslogWriter) obj; + + writer.shutdown(); + + super.destroyObject(writer); + } + + public abstract ObjectPool createPool() throws SyslogRuntimeException; + + public AbstractSyslogWriter borrowSyslogWriter() throws Exception { + AbstractSyslogWriter syslogWriter = (AbstractSyslogWriter) this.pool.borrowObject(); + + return syslogWriter; + } + + public void returnSyslogWriter(AbstractSyslogWriter syslogWriter) throws Exception { + this.pool.returnObject(syslogWriter); + } + + public void clear() throws Exception { + this.pool.clear(); + } + + public void close() throws Exception { + this.pool.close(); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/pool/generic/GenericSyslogPoolFactory.java b/src/main/java/org/productivity/java/syslog4j/impl/pool/generic/GenericSyslogPoolFactory.java new file mode 100644 index 0000000..039eaf7 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/pool/generic/GenericSyslogPoolFactory.java @@ -0,0 +1,52 @@ +package org.productivity.java.syslog4j.impl.pool.generic; + +import org.apache.commons.pool.ObjectPool; +import org.apache.commons.pool.impl.GenericObjectPool; +import org.productivity.java.syslog4j.SyslogPoolConfigIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.pool.AbstractSyslogPoolFactory; + +/** +* GenericSyslogPoolFactory is an implementation of the Apache Commons Pool +* BasePoolableObjectFactory using a GenericObjectPool. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: GenericSyslogPoolFactory.java,v 1.5 2008/12/10 04:15:10 cvs Exp $ +*/ +public class GenericSyslogPoolFactory extends AbstractSyslogPoolFactory { + protected void configureGenericObjectPool(GenericObjectPool genericObjectPool) throws SyslogRuntimeException { + SyslogPoolConfigIF poolConfig = null; + + try { + poolConfig = (SyslogPoolConfigIF) this.syslog.getConfig(); + + } catch (ClassCastException cce) { + throw new SyslogRuntimeException("config must implement interface SyslogPoolConfigIF"); + } + + genericObjectPool.setMaxActive(poolConfig.getMaxActive()); + genericObjectPool.setMaxIdle(poolConfig.getMaxIdle()); + genericObjectPool.setMaxWait(poolConfig.getMaxWait()); + genericObjectPool.setMinEvictableIdleTimeMillis(poolConfig.getMinEvictableIdleTimeMillis()); + genericObjectPool.setMinIdle(poolConfig.getMinIdle()); + genericObjectPool.setNumTestsPerEvictionRun(poolConfig.getNumTestsPerEvictionRun()); + genericObjectPool.setSoftMinEvictableIdleTimeMillis(poolConfig.getSoftMinEvictableIdleTimeMillis()); + genericObjectPool.setTestOnBorrow(poolConfig.isTestOnBorrow()); + genericObjectPool.setTestOnReturn(poolConfig.isTestOnReturn()); + genericObjectPool.setTestWhileIdle(poolConfig.isTestWhileIdle()); + genericObjectPool.setTimeBetweenEvictionRunsMillis(poolConfig.getTimeBetweenEvictionRunsMillis()); + genericObjectPool.setWhenExhaustedAction(poolConfig.getWhenExhaustedAction()); + } + + public ObjectPool createPool() throws SyslogRuntimeException { + GenericObjectPool genericPool = new GenericObjectPool(this); + + configureGenericObjectPool(genericPool); + + return genericPool; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/unix/UnixSyslog.java b/src/main/java/org/productivity/java/syslog4j/impl/unix/UnixSyslog.java new file mode 100644 index 0000000..b5e56af --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/unix/UnixSyslog.java @@ -0,0 +1,125 @@ +package org.productivity.java.syslog4j.impl.unix; + +import org.productivity.java.syslog4j.SyslogMessageProcessorIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.AbstractSyslog; +import org.productivity.java.syslog4j.impl.AbstractSyslogWriter; +import org.productivity.java.syslog4j.util.OSDetectUtility; + +import com.sun.jna.Library; +import com.sun.jna.Memory; +import com.sun.jna.Native; + +/** +* UnixSyslog is an extension of AbstractSyslog that provides support for +* Unix-based syslog clients. +* +*

This class requires the JNA (Java Native Access) library to directly +* access the native C libraries utilized on Unix platforms.

+* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: UnixSyslog.java,v 1.27 2010/10/25 04:21:19 cvs Exp $ +*/ +public class UnixSyslog extends AbstractSyslog { + private static final long serialVersionUID = 4973353204252276740L; + + protected UnixSyslogConfig unixSyslogConfig = null; + + protected interface CLibrary extends Library { + public void openlog(final Memory ident, int option, int facility); + public void syslog(int priority, final String format, final String message); + public void closelog(); + } + + protected static int currentFacility = -1; + protected static boolean openlogCalled = false; + + protected static CLibrary libraryInstance = null; + + protected static synchronized void loadLibrary(UnixSyslogConfig config) throws SyslogRuntimeException { + if (!OSDetectUtility.isUnix()) { + throw new SyslogRuntimeException("UnixSyslog not supported on non-Unix platforms"); + } + + if (libraryInstance == null) { + libraryInstance = (CLibrary) Native.loadLibrary(config.getLibrary(),CLibrary.class); + } + } + + public void initialize() throws SyslogRuntimeException { + try { + this.unixSyslogConfig = (UnixSyslogConfig) this.syslogConfig; + + } catch (ClassCastException cce) { + throw new SyslogRuntimeException("config must be of type UnixSyslogConfig"); + } + + loadLibrary(this.unixSyslogConfig); + } + + protected static void write(int level, String message, UnixSyslogConfig config) throws SyslogRuntimeException { + synchronized(libraryInstance) { + if (currentFacility != config.getFacility()) { + if (openlogCalled) { + libraryInstance.closelog(); + openlogCalled = false; + } + + currentFacility = config.getFacility(); + } + + if (!openlogCalled) { + String ident = config.getIdent(); + + if (ident != null && "".equals(ident.trim())) { + ident = null; + } + + Memory identBuffer = null; + + if (ident != null) { + identBuffer = new Memory(128); + identBuffer.setString(0, ident, false); + } + + libraryInstance.openlog(identBuffer,config.getOption(),currentFacility); + openlogCalled = true; + } + + int priority = currentFacility | level; + + libraryInstance.syslog(priority,"%s",message); + } + } + + protected void write(int level, byte[] message) throws SyslogRuntimeException { + // NO-OP + } + + public void log(SyslogMessageProcessorIF messageProcessor, int level, String message) { + write(level,message,this.unixSyslogConfig); + } + + public void flush() throws SyslogRuntimeException { + synchronized(libraryInstance) { + libraryInstance.closelog(); + openlogCalled = false; + } + } + + public void shutdown() throws SyslogRuntimeException { + flush(); + } + + public AbstractSyslogWriter getWriter() { + return null; + } + + public void returnWriter(AbstractSyslogWriter syslogWriter) { + // + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/unix/UnixSyslogConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/unix/UnixSyslogConfig.java new file mode 100644 index 0000000..7db7c82 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/unix/UnixSyslogConfig.java @@ -0,0 +1,71 @@ +package org.productivity.java.syslog4j.impl.unix; + +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.AbstractSyslogConfig; + +/** +* UnixSyslogConfig is an extension of AbstractNetSyslogConfig that provides +* configuration support for Unix-based syslog clients. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: UnixSyslogConfig.java,v 1.13 2010/10/25 03:50:25 cvs Exp $ +*/ +public class UnixSyslogConfig extends AbstractSyslogConfig { + private static final long serialVersionUID = -4805767812011660656L; + + protected String library = SYSLOG_LIBRARY_DEFAULT; + protected int option = OPTION_NONE; + + public UnixSyslogConfig() { + // Unix-based syslog does not need localName sent + this.setSendLocalName(false); + } + + public Class getSyslogClass() { + return UnixSyslog.class; + } + + public String getHost() { + return null; + } + + public int getPort() { + return 0; + } + + public void setHost(String host) throws SyslogRuntimeException { + throw new SyslogRuntimeException("Host not appropriate for class \"" + this.getClass().getName() + "\""); + } + + public void setPort(int port) throws SyslogRuntimeException { + throw new SyslogRuntimeException("Port not appropriate for class \"" + this.getClass().getName() + "\""); + } + + public String getLibrary() { + return this.library; + } + + public void setLibrary(String library) { + this.library = library; + } + + public int getOption() { + return this.option; + } + + public void setOption(int option) { + this.option = option; + } + + public int getMaxQueueSize() { + throw new SyslogRuntimeException("UnixSyslog protocol does not uses a queueing mechanism"); + } + + public void setMaxQueueSize(int maxQueueSize) { + throw new SyslogRuntimeException("UnixSyslog protocol does not uses a queueing mechanism"); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslog.java b/src/main/java/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslog.java new file mode 100644 index 0000000..eee1581 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslog.java @@ -0,0 +1,143 @@ +package org.productivity.java.syslog4j.impl.unix.socket; + +import java.nio.ByteBuffer; + +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.AbstractSyslog; +import org.productivity.java.syslog4j.impl.AbstractSyslogWriter; +import org.productivity.java.syslog4j.util.OSDetectUtility; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Structure; + +/** +* UnixSocketSyslog is an extension of AbstractSyslog that provides support for +* Unix socket-based syslog clients. +* +*

This class requires the JNA (Java Native Access) library to directly +* access the native C libraries utilized on Unix platforms.

+* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: UnixSocketSyslog.java,v 1.13 2010/11/16 00:52:01 cvs Exp $ +*/ +public class UnixSocketSyslog extends AbstractSyslog { + private static final long serialVersionUID = 39878807911936785L; + + protected static class SockAddr extends Structure { + public final static int SUN_PATH_SIZE = 108; + public final static byte[] ZERO_BYTE = new byte[] { 0 }; + + public short sun_family = 1; + public byte[] sun_path = new byte[SUN_PATH_SIZE]; + + public void setSunPath(String sunPath) { + System.arraycopy(sunPath.getBytes(), 0,this.sun_path, 0, sunPath.length()); + System.arraycopy(ZERO_BYTE,0,this.sun_path,sunPath.length(),1); + } + } + + protected interface CLibrary extends Library { + public int socket(int domain, int type, int protocol); + public int connect(int sockfd, SockAddr sockaddr, int addrlen); + public int write(int fd, ByteBuffer buffer, int count); + public int close(int fd); + public String strerror(int errno); + } + + protected boolean libraryLoaded = false; + protected CLibrary libraryInstance = null; + + protected UnixSocketSyslogConfig unixSocketSyslogConfig = null; + protected int fd = -1; + + protected synchronized void loadLibrary() { + if (!OSDetectUtility.isUnix()) { + throw new SyslogRuntimeException("UnixSyslog not supported on non-Unix platforms"); + } + + if (!this.libraryLoaded) { + this.libraryInstance = (CLibrary) Native.loadLibrary(this.unixSocketSyslogConfig.getLibrary(),CLibrary.class); + this.libraryLoaded = true; + } + } + + public void initialize() throws SyslogRuntimeException { + try { + this.unixSocketSyslogConfig = (UnixSocketSyslogConfig) this.syslogConfig; + + } catch (ClassCastException cce) { + throw new SyslogRuntimeException("config must be of type UnixSocketSyslogConfig"); + } + + loadLibrary(); + + } + + protected synchronized void connect() { + if (this.fd != -1) { + return; + } + + this.fd = this.libraryInstance.socket(this.unixSocketSyslogConfig.getFamily(),this.unixSocketSyslogConfig.getType(),this.unixSocketSyslogConfig.getProtocol()); + + if (this.fd == -1) { + this.fd = -1; + return; + } + + SockAddr sockAddr = new SockAddr(); + + sockAddr.sun_family = this.unixSocketSyslogConfig.getFamily(); + sockAddr.setSunPath(this.unixSocketSyslogConfig.getPath()); + + int c = this.libraryInstance.connect(this.fd, sockAddr, sockAddr.size()); + + if (c == -1) { + this.fd = -1; + return; + } + } + + protected void write(int level, byte[] message) throws SyslogRuntimeException { + if (this.fd == -1) { + connect(); + } + + if (this.fd == -1) { + return; + } + + ByteBuffer byteBuffer = ByteBuffer.wrap(message); + + this.libraryInstance.write(this.fd,byteBuffer,message.length); + } + + public void flush() throws SyslogRuntimeException { + shutdown(); + + this.fd = this.libraryInstance.socket(this.unixSocketSyslogConfig.getFamily(),this.unixSocketSyslogConfig.getType(),this.unixSocketSyslogConfig.getProtocol()); + } + + public void shutdown() throws SyslogRuntimeException { + if (this.fd == -1) { + return; + } + + this.libraryInstance.close(this.fd); + + this.fd = -1; + } + + public AbstractSyslogWriter getWriter() { + return null; + } + + public void returnWriter(AbstractSyslogWriter syslogWriter) { + // + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslogConfig.java b/src/main/java/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslogConfig.java new file mode 100644 index 0000000..65effb5 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslogConfig.java @@ -0,0 +1,141 @@ +package org.productivity.java.syslog4j.impl.unix.socket; + +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.impl.AbstractSyslogConfig; + +/** +* UnixSocketSyslogConfig is an extension of AbstractNetSyslogConfig that provides +* configuration support for Unix socket-based syslog clients. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: UnixSocketSyslogConfig.java,v 1.8 2010/11/12 03:43:12 cvs Exp $ +*/ +public class UnixSocketSyslogConfig extends AbstractSyslogConfig { + private static final long serialVersionUID = -3145794243736015707L; + + protected int type = SYSLOG_SOCKET_TYPE_DEFAULT; + protected short family = SYSLOG_SOCKET_FAMILY_DEFAULT; + protected int protocol = SYSLOG_SOCKET_PROTOCOL_DEFAULT; + protected String library = SYSLOG_SOCKET_LIBRARY_DEFAULT; + protected String path = SYSLOG_SOCKET_PATH_DEFAULT; + + public UnixSocketSyslogConfig() { + // Unix-based socket does not need localName sent + this.setSendLocalName(false); + this.setIdent("java"); + } + + public Class getSyslogClass() { + return UnixSocketSyslog.class; + } + + public UnixSocketSyslogConfig(int facility) { + this.facility = facility; + } + + public UnixSocketSyslogConfig(int facility, String path) { + this.facility = facility; + this.path = path; + } + + public UnixSocketSyslogConfig(String path) { + this.path = path; + } + + public String getHost() { + return null; + } + + public int getPort() { + return -1; + } + + public void setHost(String host) throws SyslogRuntimeException { + throw new SyslogRuntimeException("Host not appropriate for class \"" + this.getClass().getName() + "\""); + } + + public void setPort(int port) throws SyslogRuntimeException { + throw new SyslogRuntimeException("Port not appropriate for class \"" + this.getClass().getName() + "\""); + } + + public String getLibrary() { + return this.library; + } + + public void setLibrary(String library) { + this.library = library; + } + + public String getPath() { + return this.path; + } + + public void setPath(String path) { + this.path = path; + } + + public int getType() { + return this.type; + } + + public void setType(int type) { + this.type = type; + } + + public void setType(String type) { + if (type == null) { + throw new SyslogRuntimeException("Type cannot be null for class \"" + this.getClass().getName() + "\""); + } + + if ("SOCK_STREAM".equalsIgnoreCase(type.trim())) { + this.type = SOCK_STREAM; + + } else if ("SOCK_DGRAM".equalsIgnoreCase(type.trim())) { + this.type = SOCK_DGRAM; + + } else { + throw new SyslogRuntimeException("Type must be \"SOCK_STREAM\" or \"SOCK_DGRAM\" for class \"" + this.getClass().getName() + "\""); + } + } + + public short getFamily() { + return this.family; + } + + public void setFamily(short family) { + this.family = family; + } + + public void setFamily(String family) { + if (family == null) { + throw new SyslogRuntimeException("Family cannot be null for class \"" + this.getClass().getName() + "\""); + } + + if ("AF_UNIX".equalsIgnoreCase(family.trim())) { + this.family = AF_UNIX; + + } else { + throw new SyslogRuntimeException("Family must be \"AF_UNIX\" for class \"" + this.getClass().getName() + "\""); + } + } + + public int getProtocol() { + return this.protocol; + } + + public void setProtocol(int protocol) { + this.protocol = protocol; + } + + public int getMaxQueueSize() { + return -1; + } + + public void setMaxQueueSize(int maxQueueSize) { + throw new SyslogRuntimeException("UnixSyslog protocol does not uses a queueing mechanism"); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/SyslogServer.java b/src/main/java/org/productivity/java/syslog4j/server/SyslogServer.java new file mode 100644 index 0000000..19a70ed --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/SyslogServer.java @@ -0,0 +1,239 @@ +package org.productivity.java.syslog4j.server; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.productivity.java.syslog4j.Syslog4jVersion; +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.server.impl.net.tcp.TCPNetSyslogServerConfig; +import org.productivity.java.syslog4j.server.impl.net.udp.UDPNetSyslogServerConfig; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** + * This class provides a Singleton-based interface for Syslog4j + * server implementations. + * + *

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy + * of the LGPL license is available in the META-INF folder in all + * distributions of Syslog4j and in the base directory of the "doc" ZIP.

+ * + * @author <syslog4j@productivity.org> + * @version $Id: SyslogServer.java,v 1.14 2011/01/23 20:49:12 cvs Exp $ + */ +public class SyslogServer implements SyslogConstants { + private static final long serialVersionUID = -2260889360828258602L; + + private static boolean SUPPRESS_RUNTIME_EXCEPTIONS = false; + + protected static final Map instances = new Hashtable(); + + static { + initialize(); + } + + private SyslogServer() { + // + } + + /** + * @return Returns the current version identifier for Syslog4j. + */ + public static final String getVersion() { + return Syslog4jVersion.VERSION; + } + + + /** + * @param suppress - true to suppress throwing SyslogRuntimeException in many methods of this class, false to throw exceptions (default) + */ + public static void setSuppressRuntimeExceptions(boolean suppress) { + SUPPRESS_RUNTIME_EXCEPTIONS = suppress; + } + + /** + * @return Returns whether or not to suppress throwing SyslogRuntimeException in many methods of this class + */ + public static boolean getSuppressRuntimeExceptions() { + return SUPPRESS_RUNTIME_EXCEPTIONS; + } + + /** + * Throws SyslogRuntimeException unless it has been suppressed via setSuppressRuntimeException(boolean). + * + * @param message + * @throws SyslogRuntimeException + */ + private static void throwRuntimeException(String message) throws SyslogRuntimeException { + if (SUPPRESS_RUNTIME_EXCEPTIONS) { + return; + + } else { + throw new SyslogRuntimeException(message.toString()); + } + } + + public static final SyslogServerIF getInstance(String protocol) throws SyslogRuntimeException { + String syslogProtocol = protocol.toLowerCase(); + + if (instances.containsKey(syslogProtocol)) { + return (SyslogServerIF) instances.get(syslogProtocol); + + } else { + throwRuntimeException("SyslogServer instance \"" + syslogProtocol + "\" not defined; use \"tcp\" or \"udp\" or call SyslogServer.createInstance(protocol,config) first"); + return null; + } + } + + public static final SyslogServerIF getThreadedInstance(String protocol) throws SyslogRuntimeException { + SyslogServerIF server = getInstance(protocol); + + if (server.getThread() == null) { + Thread thread = new Thread(server); + thread.setName("SyslogServer: " + protocol); + thread.setDaemon(server.getConfig().isUseDaemonThread()); + if (server.getConfig().getThreadPriority() > -1) { + thread.setPriority(server.getConfig().getThreadPriority()); + } + + server.setThread(thread); + thread.start(); + } + + return server; + } + + public static final boolean exists(String protocol) { + if (protocol == null || "".equals(protocol.trim())) { + return false; + } + + return instances.containsKey(protocol.toLowerCase()); + } + + public static final SyslogServerIF createInstance(String protocol, SyslogServerConfigIF config) throws SyslogRuntimeException { + if (protocol == null || "".equals(protocol.trim())) { + throwRuntimeException("Instance protocol cannot be null or empty"); + return null; + } + + if (config == null) { + throwRuntimeException("SyslogServerConfig cannot be null"); + return null; + } + + String syslogProtocol = protocol.toLowerCase(); + + SyslogServerIF syslogServer = null; + + synchronized(instances) { + if (instances.containsKey(syslogProtocol)) { + throwRuntimeException("SyslogServer instance \"" + syslogProtocol + "\" already defined."); + return null; + } + + try { + Class syslogClass = config.getSyslogServerClass(); + + syslogServer = (SyslogServerIF) syslogClass.newInstance(); + + } catch (ClassCastException cse) { + throw new SyslogRuntimeException(cse); + + } catch (IllegalAccessException iae) { + throw new SyslogRuntimeException(iae); + + } catch (InstantiationException ie) { + throw new SyslogRuntimeException(ie); + } + + syslogServer.initialize(syslogProtocol,config); + + instances.put(syslogProtocol,syslogServer); + } + + return syslogServer; + } + + public static final SyslogServerIF createThreadedInstance(String protocol, SyslogServerConfigIF config) throws SyslogRuntimeException { + createInstance(protocol,config); + + SyslogServerIF server = getThreadedInstance(protocol); + + return server; + } + + public synchronized static final void destroyInstance(String protocol) { + if (protocol == null || "".equals(protocol.trim())) { + return; + } + + String _protocol = protocol.toLowerCase(); + + if (instances.containsKey(_protocol)) { + SyslogUtility.sleep(SyslogConstants.THREAD_LOOP_INTERVAL_DEFAULT); + + SyslogServerIF syslogServer = (SyslogServerIF) instances.get(_protocol); + + try { + syslogServer.shutdown(); + + } finally { + instances.remove(_protocol); + } + + } else { + throwRuntimeException("Cannot destroy server protocol \"" + protocol + "\" instance; call shutdown instead"); + return; + } + } + + public synchronized static final void destroyInstance(SyslogServerIF syslogServer) { + if (syslogServer == null) { + return; + } + + String protocol = syslogServer.getProtocol().toLowerCase(); + + if (instances.containsKey(protocol)) { + SyslogUtility.sleep(SyslogConstants.THREAD_LOOP_INTERVAL_DEFAULT); + + try { + syslogServer.shutdown(); + + } finally { + instances.remove(protocol); + } + + } else { + throwRuntimeException("Cannot destroy server protocol \"" + protocol + "\" instance; call shutdown instead"); + } + } + + public synchronized static void initialize() { + createInstance(UDP,new UDPNetSyslogServerConfig()); + createInstance(TCP,new TCPNetSyslogServerConfig()); + } + + public synchronized static final void shutdown() throws SyslogRuntimeException { + Set protocols = instances.keySet(); + + Iterator i = protocols.iterator(); + + while(i.hasNext()) { + String protocol = (String) i.next(); + + SyslogServerIF syslogServer = (SyslogServerIF) instances.get(protocol); + + syslogServer.shutdown(); + } + + instances.clear(); + } + + public static void main(String[] args) throws Exception { + SyslogServerMain.main(args); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/SyslogServerConfigIF.java b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerConfigIF.java new file mode 100644 index 0000000..f0e5491 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerConfigIF.java @@ -0,0 +1,50 @@ +package org.productivity.java.syslog4j.server; + +import java.util.List; + +import org.productivity.java.syslog4j.SyslogCharSetIF; +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogRuntimeException; + +/** +* SyslogServerConfigIF provides a common, extensible configuration interface for all +* implementations of SyslogServerIF. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogServerConfigIF.java,v 1.12 2011/01/11 05:11:13 cvs Exp $ +*/ +public interface SyslogServerConfigIF extends SyslogConstants, SyslogCharSetIF { + public Class getSyslogServerClass(); + + public String getHost(); + public void setHost(String host) throws SyslogRuntimeException; + + public int getPort(); + public void setPort(int port) throws SyslogRuntimeException; + + public boolean isUseDaemonThread(); + public void setUseDaemonThread(boolean useDaemonThread); + + public int getThreadPriority(); + public void setThreadPriority(int threadPriority); + + public List getEventHandlers(); + + public long getShutdownWait(); + public void setShutdownWait(long shutdownWait); + + public void addEventHandler(SyslogServerEventHandlerIF eventHandler); + public void insertEventHandler(int pos, SyslogServerEventHandlerIF eventHandler); + public void removeEventHandler(SyslogServerEventHandlerIF eventHandler); + public void removeAllEventHandlers(); + + public boolean isUseStructuredData(); + public void setUseStructuredData(boolean useStructuredData); + + public Object getDateTimeFormatter(); + public void setDateTimeFormatter(Object dateTimeFormatter); +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/SyslogServerEventHandlerIF.java b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerEventHandlerIF.java new file mode 100644 index 0000000..5d60558 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerEventHandlerIF.java @@ -0,0 +1,8 @@ +package org.productivity.java.syslog4j.server; + +import java.io.Serializable; + +public abstract interface SyslogServerEventHandlerIF extends Serializable { + public void initialize(SyslogServerIF syslogServer); + public void destroy(SyslogServerIF syslogServer); +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/SyslogServerEventIF.java b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerEventIF.java new file mode 100644 index 0000000..cc578e0 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerEventIF.java @@ -0,0 +1,41 @@ +package org.productivity.java.syslog4j.server; + +import java.util.Date; + +import org.productivity.java.syslog4j.SyslogCharSetIF; + +/** +* SyslogServerEventIF provides an extensible interface for Syslog4j +* server events. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogServerEventIF.java,v 1.4 2010/11/28 01:38:08 cvs Exp $ +*/ +public interface SyslogServerEventIF extends SyslogCharSetIF { + /** + * Note: getRaw() may use System.arraycopy(..) each time it is called; best to call it once and store the result. + * + * @return Returns the raw data received from the client. + */ + public byte[] getRaw(); + + public int getFacility(); + public void setFacility(int facility); + + public Date getDate(); + public void setDate(Date date); + + public int getLevel(); + public void setLevel(int level); + + public String getHost(); + public void setHost(String host); + public boolean isHostStrippedFromMessage(); + + public String getMessage(); + public void setMessage(String message); +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/SyslogServerIF.java b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerIF.java new file mode 100644 index 0000000..42f4433 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerIF.java @@ -0,0 +1,27 @@ +package org.productivity.java.syslog4j.server; + +import org.productivity.java.syslog4j.SyslogRuntimeException; + +/** +* SyslogServerIF provides a common interface for all Syslog4j server implementations. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogServerIF.java,v 1.5 2008/11/07 15:15:41 cvs Exp $ +*/ +public interface SyslogServerIF extends Runnable { + public void initialize(String protocol, SyslogServerConfigIF config) throws SyslogRuntimeException; + + public String getProtocol(); + public SyslogServerConfigIF getConfig(); + + public void run(); + + public Thread getThread(); + public void setThread(Thread thread); + + public void shutdown(); +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/SyslogServerMain.java b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerMain.java new file mode 100644 index 0000000..6637f94 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerMain.java @@ -0,0 +1,165 @@ +package org.productivity.java.syslog4j.server; + +import org.productivity.java.syslog4j.server.impl.event.printstream.FileSyslogServerEventHandler; +import org.productivity.java.syslog4j.server.impl.event.printstream.SystemOutSyslogServerEventHandler; +import org.productivity.java.syslog4j.server.impl.net.tcp.TCPNetSyslogServerConfigIF; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** + * This class provides a command-line interface for Syslog4j + * server implementations. + * + *

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy + * of the LGPL license is available in the META-INF folder in all + * distributions of Syslog4j and in the base directory of the "doc" ZIP.

+ * + * @author <syslog4j@productivity.org> + * @version $Id: SyslogServerMain.java,v 1.3 2010/11/28 01:38:08 cvs Exp $ + */ +public class SyslogServerMain { + public static boolean CALL_SYSTEM_EXIT_ON_FAILURE = true; + + public static class Options { + public String protocol = null; + public String fileName = null; + public boolean append = false; + public boolean quiet = false; + + public String host = null; + public String port = null; + public String timeout = null; + + public String usage = null; + } + + public static void usage(String problem) { + if (problem != null) { + System.out.println("Error: " + problem); + System.out.println(); + } + + System.out.println("Usage:"); + System.out.println(); + System.out.println("SyslogServer [-h ] [-p ] [-o ] [-a] [-q] "); + System.out.println(); + System.out.println("-h host or IP to bind"); + System.out.println("-p port to bind"); + System.out.println("-t socket timeout (in milliseconds)"); + System.out.println("-o file to write entries (overwrites by default)"); + System.out.println(); + System.out.println("-a append to file (instead of overwrite)"); + System.out.println("-q do not write anything to standard out"); + System.out.println(); + System.out.println("protocol Syslog4j protocol implementation (tcp, udp, ...)"); + } + + public static Options parseOptions(String[] args) { + Options options = new Options(); + + int i = 0; + while(i < args.length) { + String arg = args[i++]; + boolean match = false; + + if ("-h".equals(arg)) { if (i == args.length) { options.usage = "Must specify host with -h"; return options; } match = true; options.host = args[i++]; } + if ("-p".equals(arg)) { if (i == args.length) { options.usage = "Must specify port with -p"; return options; } match = true; options.port = args[i++]; } + if ("-t".equals(arg)) { if (i == args.length) { options.usage = "Must specify value (in milliseconds)"; return options; } match = true; options.timeout = args[i++]; } + if ("-o".equals(arg)) { if (i == args.length) { options.usage = "Must specify file with -o"; return options; } match = true; options.fileName = args[i++]; } + + if ("-a".equals(arg)) { match = true; options.append = true; } + if ("-q".equals(arg)) { match = true; options.quiet = true; } + + if (!match) { + if (options.protocol != null) { + options.usage = "Only one protocol definition allowed"; + return options; + } + + options.protocol = arg; + } + } + + if (options.protocol == null) { + options.usage = "Must specify protocol"; + return options; + } + + if (options.fileName == null && options.append) { + options.usage = "Cannot specify -a without specifying -f "; + return options; + } + + return options; + } + + public static void main(String[] args) throws Exception { + Options options = parseOptions(args); + + if (options.usage != null) { + usage(options.usage); + if (CALL_SYSTEM_EXIT_ON_FAILURE) { System.exit(1); } else { return; } + } + + if (!options.quiet) { + System.out.println("SyslogServer " + SyslogServer.getVersion()); + } + + if (!SyslogServer.exists(options.protocol)) { + usage("Protocol \"" + options.protocol + "\" not supported"); + if (CALL_SYSTEM_EXIT_ON_FAILURE) { System.exit(1); } else { return; } + } + + SyslogServerIF syslogServer = SyslogServer.getInstance(options.protocol); + + SyslogServerConfigIF syslogServerConfig = syslogServer.getConfig(); + + if (options.host != null) { + syslogServerConfig.setHost(options.host); + if (!options.quiet) { + System.out.println("Listening on host: " + options.host); + } + } + + if (options.port != null) { + syslogServerConfig.setPort(Integer.parseInt(options.port)); + if (!options.quiet) { + System.out.println("Listening on port: " + options.port); + } + } + + if (options.timeout != null) { + if (syslogServerConfig instanceof TCPNetSyslogServerConfigIF) { + ((TCPNetSyslogServerConfigIF) syslogServerConfig).setTimeout(Integer.parseInt(options.timeout)); + if (!options.quiet) { + System.out.println("Timeout: " + options.timeout); + } + + } else { + System.err.println("Timeout not supported for protocol \"" + options.protocol + "\" (ignored)"); + } + } + + if (options.fileName != null) { + SyslogServerEventHandlerIF eventHandler = new FileSyslogServerEventHandler(options.fileName,options.append); + syslogServerConfig.addEventHandler(eventHandler); + if (!options.quiet) { + System.out.println((options.append ? "Appending" : "Writing") + " to file: " + options.fileName); + } + } + + if (!options.quiet) { + SyslogServerEventHandlerIF eventHandler = SystemOutSyslogServerEventHandler.create(); + syslogServerConfig.addEventHandler(eventHandler); + } + + if (!options.quiet) { + System.out.println(); + } + + SyslogServer.getThreadedInstance(options.protocol); + + while(true) { + SyslogUtility.sleep(1000); + } + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/SyslogServerSessionEventHandlerIF.java b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerSessionEventHandlerIF.java new file mode 100644 index 0000000..f1b7374 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerSessionEventHandlerIF.java @@ -0,0 +1,10 @@ +package org.productivity.java.syslog4j.server; + +import java.net.SocketAddress; + +public interface SyslogServerSessionEventHandlerIF extends SyslogServerEventHandlerIF { + public Object sessionOpened(SyslogServerIF syslogServer, SocketAddress socketAddress); + public void event(Object session, SyslogServerIF syslogServer, SocketAddress socketAddress, SyslogServerEventIF event); + public void exception(Object session, SyslogServerIF syslogServer, SocketAddress socketAddress, Exception exception); + public void sessionClosed(Object session, SyslogServerIF syslogServer, SocketAddress socketAddress, boolean timeout); +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/SyslogServerSessionlessEventHandlerIF.java b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerSessionlessEventHandlerIF.java new file mode 100644 index 0000000..e9c2bb2 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/SyslogServerSessionlessEventHandlerIF.java @@ -0,0 +1,20 @@ +package org.productivity.java.syslog4j.server; + +import java.net.SocketAddress; + + +/** +* SyslogServerEventHandlerIF provides an extensible interface for Syslog4j +* server event handlers. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogServerSessionlessEventHandlerIF.java,v 1.1 2010/11/12 02:56:44 cvs Exp $ +*/ +public interface SyslogServerSessionlessEventHandlerIF extends SyslogServerEventHandlerIF { + public void event(SyslogServerIF syslogServer, SocketAddress socketAddress, SyslogServerEventIF event); + public void exception(SyslogServerIF syslogServer, SocketAddress socketAddress, Exception exception); +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/AbstractSyslogServer.java b/src/main/java/org/productivity/java/syslog4j/server/impl/AbstractSyslogServer.java new file mode 100644 index 0000000..d8cc44b --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/AbstractSyslogServer.java @@ -0,0 +1,339 @@ +package org.productivity.java.syslog4j.server.impl; + +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.productivity.java.syslog4j.SyslogCharSetIF; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.server.SyslogServerConfigIF; +import org.productivity.java.syslog4j.server.SyslogServerEventHandlerIF; +import org.productivity.java.syslog4j.server.SyslogServerEventIF; +import org.productivity.java.syslog4j.server.SyslogServerIF; +import org.productivity.java.syslog4j.server.SyslogServerSessionEventHandlerIF; +import org.productivity.java.syslog4j.server.SyslogServerSessionlessEventHandlerIF; +import org.productivity.java.syslog4j.server.impl.event.SyslogServerEvent; +import org.productivity.java.syslog4j.server.impl.event.structured.StructuredSyslogServerEvent; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* AbstractSyslogServer provides a base abstract implementation of the SyslogServerIF. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractSyslogServer.java,v 1.12 2011/01/11 05:11:13 cvs Exp $ +*/ +public abstract class AbstractSyslogServer implements SyslogServerIF { + public static class Sessions extends HashMap { + private static final long serialVersionUID = -4438949276263772580L; + + public static final Object syncObject = new Object(); + + public void addSocket(Socket socket) { + synchronized(syncObject) { + put(socket,new HashMap()); + } + } + + public Iterator getSockets() { + if (size() > 0) { + return keySet().iterator(); + + } else { + return null; + } + } + + public void addSession(Socket socket, SyslogServerEventHandlerIF eventHandler, Object session) { + synchronized(syncObject) { + Map handlerMap = getHandlerMap(socket); + + if (handlerMap == null) { + handlerMap = new HashMap(); + } + + handlerMap.put(eventHandler,session); + } + } + + public void removeSocket(Socket socket) { + synchronized(syncObject) { + Map handlerMap = getHandlerMap(socket); + + if (handlerMap != null) { + handlerMap.clear(); + } + } + } + + protected Map getHandlerMap(Socket socket) { + Map handlerMap = null; + + if (containsKey(socket)) { + handlerMap = (Map) get(socket); + } + + return handlerMap; + } + + public Object getSession(Socket socket, SyslogServerEventHandlerIF eventHandler) { + synchronized(syncObject) { + Map handlerMap = getHandlerMap(socket); + + Object session = handlerMap.get(eventHandler); + + return session; + } + } + } + + protected String syslogProtocol = null; + protected AbstractSyslogServerConfig syslogServerConfig = null; + protected Thread thread = null; + + protected boolean shutdown = false; + + public void initialize(String protocol, SyslogServerConfigIF config) throws SyslogRuntimeException { + this.syslogProtocol = protocol; + + try { + this.syslogServerConfig = (AbstractSyslogServerConfig) config; + + } catch (ClassCastException cce) { + throw new SyslogRuntimeException(cce); + } + + initialize(); + } + + public String getProtocol() { + return this.syslogProtocol; + } + + public SyslogServerConfigIF getConfig() { + return this.syslogServerConfig; + } + + protected abstract void initialize() throws SyslogRuntimeException; + + public void shutdown() throws SyslogRuntimeException { + this.shutdown = true; + } + + public Thread getThread() { + return this.thread; + } + + public void setThread(Thread thread) { + this.thread = thread; + } + + protected static boolean isStructuredMessage(SyslogCharSetIF syslogCharSet, byte[] receiveData) { + String receiveDataString = SyslogUtility.newString(syslogCharSet, receiveData); + + boolean isStructuredMessage = isStructuredMessage(syslogCharSet,receiveDataString); + + return isStructuredMessage; + } + + protected static boolean isStructuredMessage(SyslogCharSetIF syslogCharSet, String receiveData) { + int idx = receiveData.indexOf('>'); + + if (idx != -1) { + // If there's a numerical VERSION field after the , return true. + if (receiveData.length() > idx + 1 && Character.isDigit(receiveData.charAt(idx + 1))) { + return true; + } + } + + return false; + } + + protected static SyslogServerEventIF createEvent(SyslogServerConfigIF serverConfig, byte[] lineBytes, int lineBytesLength, InetAddress inetAddr) { + SyslogServerEventIF event = null; + + if (serverConfig.isUseStructuredData() && AbstractSyslogServer.isStructuredMessage(serverConfig,lineBytes)) { + event = new StructuredSyslogServerEvent(lineBytes,lineBytesLength,inetAddr); + + if (serverConfig.getDateTimeFormatter() != null) { + ((StructuredSyslogServerEvent) event).setDateTimeFormatter(serverConfig.getDateTimeFormatter()); + } + + } else { + event = new SyslogServerEvent(lineBytes,lineBytesLength,inetAddr); + } + + return event; + } + + protected static SyslogServerEventIF createEvent(SyslogServerConfigIF serverConfig, String line, InetAddress inetAddr) { + SyslogServerEventIF event = null; + + if (serverConfig.isUseStructuredData() && AbstractSyslogServer.isStructuredMessage(serverConfig,line)) { + event = new StructuredSyslogServerEvent(line,inetAddr); + + } else { + event = new SyslogServerEvent(line,inetAddr); + } + + return event; + } + + public static void handleInitialize(SyslogServerIF syslogServer) { + List eventHandlers = syslogServer.getConfig().getEventHandlers(); + + for(int i=0; iSyslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractSyslogServerConfig.java,v 1.9 2011/01/11 05:11:13 cvs Exp $ +*/ +public abstract class AbstractSyslogServerConfig implements SyslogServerConfigIF { + private static final long serialVersionUID = 870248648801259856L; + + public abstract Class getSyslogServerClass(); + + protected String charSet = CHAR_SET_DEFAULT; + + protected long shutdownWait = SyslogConstants.SERVER_SHUTDOWN_WAIT_DEFAULT; + + protected List eventHandlers = new ArrayList(); + + protected boolean useStructuredData = USE_STRUCTURED_DATA_DEFAULT; + + protected Object dateTimeFormatter = null; + + protected boolean useDaemonThread = USE_DAEMON_THREAD_DEFAULT; + protected int threadPriority = THREAD_PRIORITY_DEFAULT; + + public String getCharSet() { + return this.charSet; + } + + public void setCharSet(String charSet) { + this.charSet = charSet; + } + + public long getShutdownWait() { + return this.shutdownWait; + } + + public void setShutdownWait(long shutdownWait) { + this.shutdownWait = shutdownWait; + } + + public List getEventHandlers() { + return this.eventHandlers; + } + + public void addEventHandler(SyslogServerEventHandlerIF eventHandler) { + this.eventHandlers.add(eventHandler); + } + + public void insertEventHandler(int pos, SyslogServerEventHandlerIF eventHandler) { + this.eventHandlers.add(pos, eventHandler); + } + + public void removeEventHandler(SyslogServerEventHandlerIF eventHandler) { + this.eventHandlers.remove(eventHandler); + } + + public void removeAllEventHandlers() { + this.eventHandlers.clear(); + } + + public boolean isUseStructuredData() { + return useStructuredData; + } + + public void setUseStructuredData(boolean useStructuredData) { + this.useStructuredData = useStructuredData; + } + + public boolean isUseDaemonThread() { + return useDaemonThread; + } + + public Object getDateTimeFormatter() { + return dateTimeFormatter; + } + + public void setDateTimeFormatter(Object dateTimeFormatter) { + this.dateTimeFormatter = dateTimeFormatter; + } + + public void setUseDaemonThread(boolean useDaemonThread) { + this.useDaemonThread = useDaemonThread; + } + + public int getThreadPriority() { + return threadPriority; + } + + public void setThreadPriority(int threadPriority) { + this.threadPriority = threadPriority; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/event/SyslogServerEvent.java b/src/main/java/org/productivity/java/syslog4j/server/impl/event/SyslogServerEvent.java new file mode 100644 index 0000000..bd63bde --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/event/SyslogServerEvent.java @@ -0,0 +1,213 @@ +package org.productivity.java.syslog4j.server.impl.event; + +import java.net.InetAddress; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; + +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.server.SyslogServerEventIF; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* SyslogServerEvent provides an implementation of the SyslogServerEventIF interface. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogServerEvent.java,v 1.9 2011/01/11 06:21:15 cvs Exp $ +*/ +public class SyslogServerEvent implements SyslogServerEventIF { + private static final long serialVersionUID = 6136043067089899962L; + + public static final String DATE_FORMAT = "MMM dd HH:mm:ss yyyy"; + public static final String DATE_FORMAT_S = "MMM d HH:mm:ss yyyy"; + + protected String charSet = SyslogConstants.CHAR_SET_DEFAULT; + protected String rawString = null; + protected byte[] rawBytes = null; + protected int rawLength = -1; + protected Date date = null; + protected int level = -1; + protected int facility = -1; + protected String host = null; + protected boolean isHostStrippedFromMessage = false; + protected String message = null; + protected InetAddress inetAddress = null; + + protected SyslogServerEvent() { } + + public SyslogServerEvent(final String message, InetAddress inetAddress) { + initialize(message,inetAddress); + + parse(); + } + + public SyslogServerEvent(final byte[] message, int length, InetAddress inetAddress) { + initialize(message,length,inetAddress); + + parse(); + } + + protected void initialize(final String message, InetAddress inetAddress) { + this.rawString = message; + this.rawLength = message.length(); + this.inetAddress = inetAddress; + + this.message = message; + } + + protected void initialize(final byte[] message, int length, InetAddress inetAddress) { + this.rawBytes = message; + this.rawLength = length; + this.inetAddress = inetAddress; + } + + protected void parseHost() { + int i = this.message.indexOf(' '); + + if (i > -1) { + this.host = this.message.substring(0,i).trim(); + } + } + + protected void parseDate() { + int datelength = 16; + String dateFormatS = DATE_FORMAT; + + if (this.message.length() > datelength) { + + // http://jira.graylog2.org/browse/SERVER-287 + if (this.message.charAt(5) == ' ') { + datelength = 15; + dateFormatS = DATE_FORMAT_S; + } + + String year = Integer.toString(Calendar.getInstance().get(Calendar.YEAR)); + + String originalDate = this.message.substring(0,datelength-1) + " " + year; + DateFormat dateFormat = new SimpleDateFormat(dateFormatS); + try { + this.date = dateFormat.parse(originalDate); + + this.message = this.message.substring(datelength); + + } catch (ParseException pe) { + this.date = new Date(); + } + } + + parseHost(); + } + + protected void parsePriority() { + if (this.message.charAt(0) == '<') { + int i = this.message.indexOf(">"); + + if (i <= 4 && i > -1) { + String priorityStr = this.message.substring(1,i); + + int priority = 0; + try { + priority = Integer.parseInt(priorityStr); + this.facility = priority >> 3; + this.level = priority - (this.facility << 3); + + this.message = this.message.substring(i+1); + + parseDate(); + + } catch (NumberFormatException nfe) { + // + } + + parseHost(); + } + } + } + + protected void parse() { + if (this.message == null) { + this.message = SyslogUtility.newString(this,this.rawBytes,this.rawLength); + } + + parsePriority(); + } + + public int getFacility() { + return this.facility; + } + + public void setFacility(int facility) { + this.facility = facility; + } + + public byte[] getRaw() { + if (this.rawString != null) { + byte[] rawStringBytes = SyslogUtility.getBytes(this,this.rawString); + + return rawStringBytes; + + } else if (this.rawBytes.length == this.rawLength) { + return this.rawBytes; + + } else { + byte[] newRawBytes = new byte[this.rawLength]; + System.arraycopy(this.rawBytes,0,newRawBytes,0,this.rawLength); + + return newRawBytes; + } + } + + public int getRawLength() { + return this.rawLength; + } + + public Date getDate() { + return this.date; + } + + public void setDate(Date date) { + this.date = date; + } + + public int getLevel() { + return this.level; + } + + public void setLevel(int level) { + this.level = level; + } + + public String getHost() { + return this.host; + } + + public void setHost(String host) { + this.host = host; + } + + public boolean isHostStrippedFromMessage() { + return isHostStrippedFromMessage; + } + + public String getMessage() { + return this.message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getCharSet() { + return this.charSet; + } + + public void setCharSet(String charSet) { + this.charSet = charSet; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/FileSyslogServerEventHandler.java b/src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/FileSyslogServerEventHandler.java new file mode 100644 index 0000000..7bf53b4 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/FileSyslogServerEventHandler.java @@ -0,0 +1,29 @@ +package org.productivity.java.syslog4j.server.impl.event.printstream; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; + +public class FileSyslogServerEventHandler extends PrintStreamSyslogServerEventHandler { + private static final long serialVersionUID = -755824686809731430L; + + protected static PrintStream createPrintStream(String fileName, boolean append) throws IOException { + File file = new File(fileName); + + OutputStream os = new FileOutputStream(file,append); + + PrintStream printStream = new PrintStream(os); + + return printStream; + } + + public FileSyslogServerEventHandler(String fileName) throws IOException { + super(createPrintStream(fileName,true)); + } + + public FileSyslogServerEventHandler(String fileName, boolean append) throws IOException { + super(createPrintStream(fileName,append)); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/PrintStreamSyslogServerEventHandler.java b/src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/PrintStreamSyslogServerEventHandler.java new file mode 100644 index 0000000..d161916 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/PrintStreamSyslogServerEventHandler.java @@ -0,0 +1,59 @@ +package org.productivity.java.syslog4j.server.impl.event.printstream; + +import java.io.PrintStream; +import java.net.SocketAddress; +import java.util.Date; + +import org.productivity.java.syslog4j.server.SyslogServerEventIF; +import org.productivity.java.syslog4j.server.SyslogServerIF; +import org.productivity.java.syslog4j.server.SyslogServerSessionEventHandlerIF; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* SystemOutSyslogServerEventHandler provides a simple example implementation +* of the SyslogServerEventHandlerIF which writes the events to System.out. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: PrintStreamSyslogServerEventHandler.java,v 1.7 2010/11/28 22:07:57 cvs Exp $ +*/ +public class PrintStreamSyslogServerEventHandler implements SyslogServerSessionEventHandlerIF { + private static final long serialVersionUID = 6036415838696050746L; + + protected PrintStream stream = null; + + public PrintStreamSyslogServerEventHandler(PrintStream stream) { + this.stream = stream; + } + + public void initialize(SyslogServerIF syslogServer) { + return; + } + + public Object sessionOpened(SyslogServerIF syslogServer, SocketAddress socketAddress) { + return null; + } + + public void event(Object session, SyslogServerIF syslogServer, SocketAddress socketAddress, SyslogServerEventIF event) { + String date = (event.getDate() == null ? new Date() : event.getDate()).toString(); + String facility = SyslogUtility.getFacilityString(event.getFacility()); + String level = SyslogUtility.getLevelString(event.getLevel()); + + this.stream.println("{" + facility + "} " + date + " " + level + " " + event.getMessage()); + } + + public void exception(Object session, SyslogServerIF syslogServer, SocketAddress socketAddress, Exception exception) { + // + } + + public void sessionClosed(Object session, SyslogServerIF syslogServer, SocketAddress socketAddress, boolean timeout) { + // + } + + public void destroy(SyslogServerIF syslogServer) { + return; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/SystemErrSyslogServerEventHandler.java b/src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/SystemErrSyslogServerEventHandler.java new file mode 100644 index 0000000..e61052e --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/SystemErrSyslogServerEventHandler.java @@ -0,0 +1,15 @@ +package org.productivity.java.syslog4j.server.impl.event.printstream; + +import org.productivity.java.syslog4j.server.SyslogServerSessionEventHandlerIF; + +public class SystemErrSyslogServerEventHandler extends PrintStreamSyslogServerEventHandler { + private static final long serialVersionUID = -3496862887351690575L; + + public static SyslogServerSessionEventHandlerIF create() { + return new SystemErrSyslogServerEventHandler(); + } + + public SystemErrSyslogServerEventHandler() { + super(System.err); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/SystemOutSyslogServerEventHandler.java b/src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/SystemOutSyslogServerEventHandler.java new file mode 100644 index 0000000..bfe38b8 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/event/printstream/SystemOutSyslogServerEventHandler.java @@ -0,0 +1,15 @@ +package org.productivity.java.syslog4j.server.impl.event.printstream; + +import org.productivity.java.syslog4j.server.SyslogServerSessionEventHandlerIF; + +public class SystemOutSyslogServerEventHandler extends PrintStreamSyslogServerEventHandler { + private static final long serialVersionUID = 1690551409588182601L; + + public static SyslogServerSessionEventHandlerIF create() { + return new SystemOutSyslogServerEventHandler(); + } + + public SystemOutSyslogServerEventHandler() { + super(System.out); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/event/structured/StructuredSyslogServerEvent.java b/src/main/java/org/productivity/java/syslog4j/server/impl/event/structured/StructuredSyslogServerEvent.java new file mode 100644 index 0000000..476f3ab --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/event/structured/StructuredSyslogServerEvent.java @@ -0,0 +1,151 @@ +package org.productivity.java.syslog4j.server.impl.event.structured; + +import java.net.InetAddress; + +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.impl.message.structured.StructuredSyslogMessage; +import org.productivity.java.syslog4j.server.impl.event.SyslogServerEvent; + +/** + * SyslogServerStructuredEvent provides an implementation of the + * SyslogServerEventIF interface that supports receiving of structured syslog + * messages, as defined in: + * + *

+ * http://tools.ietf.org/html/draft-ietf-syslog-protocol-23#section-6 + *

+ * + *

+ * Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy of the + * LGPL license is available in the META-INF folder in all distributions of + * Syslog4j and in the base directory of the "doc" ZIP. + *

+ * + * @author Manish Motwani + * @version $Id: StructuredSyslogServerEvent.java,v 1.6 2011/01/11 05:11:13 cvs Exp $ + */ +public class StructuredSyslogServerEvent extends SyslogServerEvent { + private static final long serialVersionUID = 1676499796406044315L; + + protected String applicationName = SyslogConstants.STRUCTURED_DATA_APP_NAME_DEFAULT_VALUE; + protected String processId = null; + protected DateTime dateTime = null; + protected DateTimeFormatter dateTimeFormatter = null; + + public StructuredSyslogServerEvent(final byte[] message, int length, InetAddress inetAddress) { + super(); + + initialize(message,length,inetAddress); + parse(); + } + + public StructuredSyslogServerEvent(final String message, InetAddress inetAddress) { + super(); + + initialize(message,inetAddress); + parse(); + } + + public DateTimeFormatter getDateTimeFormatter() { + if (dateTimeFormatter == null) { + this.dateTimeFormatter = ISODateTimeFormat.dateTime(); + } + + return dateTimeFormatter; + } + + public void setDateTimeFormatter(Object dateTimeFormatter) { + this.dateTimeFormatter = (DateTimeFormatter) dateTimeFormatter; + } + + protected void parseApplicationName() { + int i = this.message.indexOf(' '); + + if (i > -1) { + this.applicationName = this.message.substring(0, i).trim(); + this.message = this.message.substring(i + 1); + parseProcessId(); + } + + if (SyslogConstants.STRUCTURED_DATA_NILVALUE.equals(this.applicationName)) { + this.applicationName = null; + } + } + + protected void parseProcessId() { + int i = this.message.indexOf(' '); + + if (i > -1) { + this.processId = this.message.substring(0, i).trim(); + this.message = this.message.substring(i + 1); + } + + if (SyslogConstants.STRUCTURED_DATA_NILVALUE.equals(this.processId)) { + this.processId = null; + } + } + + protected void parseDate() { + // skip VERSION field + int i = this.message.indexOf(' '); + this.message = this.message.substring(i + 1); + + // parse the date + i = this.message.indexOf(' '); + + if (i > -1) { + String dateString = this.message.substring(0, i).trim(); + + try { + DateTimeFormatter formatter = getDateTimeFormatter(); + + this.dateTime = formatter.parseDateTime(dateString); + this.date = this.dateTime.toDate(); + + this.message = this.message.substring(dateString.length() + 1); + + } catch (Exception e) { + // Not structured date format, try super one + super.parseDate(); + } + } + } + + protected void parseHost() { + int i = this.message.indexOf(' '); + + if (i > -1) { + this.host = this.message.substring(0,i).trim(); + this.message = this.message.substring(i+1); + + parseApplicationName(); + } + } + + public String getApplicationName() { + return this.applicationName; + } + + public String getProcessId() { + return this.processId; + } + + public DateTime getDateTime() { + return this.dateTime; + } + + public StructuredSyslogMessage getStructuredMessage() { + try { + return StructuredSyslogMessage.fromString(getMessage()); + + } catch (IllegalArgumentException e) { + // throw new SyslogRuntimeException( + // "Message received is not a valid structured message: " + // + getMessage(), e); + return new StructuredSyslogMessage(null,null,getMessage()); + } + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/net/AbstractNetSyslogServerConfig.java b/src/main/java/org/productivity/java/syslog4j/server/impl/net/AbstractNetSyslogServerConfig.java new file mode 100644 index 0000000..31067f4 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/net/AbstractNetSyslogServerConfig.java @@ -0,0 +1,37 @@ +package org.productivity.java.syslog4j.server.impl.net; + +import org.productivity.java.syslog4j.server.impl.AbstractSyslogServerConfig; + +/** +* AbstractNetSyslogServerConfig provides a base abstract implementation of the AbstractSyslogServerConfig +* configuration interface. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: AbstractNetSyslogServerConfig.java,v 1.4 2008/11/07 15:15:41 cvs Exp $ +*/ +public abstract class AbstractNetSyslogServerConfig extends AbstractSyslogServerConfig { + private static final long serialVersionUID = -3363374941938350263L; + + protected String host = null; + protected int port = SYSLOG_PORT_DEFAULT; + + public String getHost() { + return this.host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return this.port; + } + + public void setPort(int port) { + this.port = port; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServer.java b/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServer.java new file mode 100644 index 0000000..9e47937 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServer.java @@ -0,0 +1,252 @@ +package org.productivity.java.syslog4j.server.impl.net.tcp; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.util.Iterator; + +import javax.net.ServerSocketFactory; + +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.server.SyslogServerEventIF; +import org.productivity.java.syslog4j.server.SyslogServerIF; +import org.productivity.java.syslog4j.server.impl.AbstractSyslogServer; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* TCPNetSyslogServer provides a simple threaded TCP/IP server implementation. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: TCPNetSyslogServer.java,v 1.23 2010/11/28 22:07:57 cvs Exp $ +*/ +public class TCPNetSyslogServer extends AbstractSyslogServer { + public static class TCPNetSyslogSocketHandler implements Runnable { + protected SyslogServerIF server = null; + protected Socket socket = null; + protected Sessions sessions = null; + + public TCPNetSyslogSocketHandler(Sessions sessions, SyslogServerIF server, Socket socket) { + this.sessions = sessions; + this.server = server; + this.socket = socket; + + synchronized(this.sessions) { + this.sessions.addSocket(socket); + } + } + + public void run() { + boolean timeout = false; + + try { + BufferedReader br = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); + + String line = br.readLine(); + + if (line != null) { + AbstractSyslogServer.handleSessionOpen(this.sessions,this.server,this.socket); + } + + while (line != null && line.length() != 0) { + SyslogServerEventIF event = createEvent(this.server.getConfig(),line,this.socket.getInetAddress()); + + AbstractSyslogServer.handleEvent(this.sessions,this.server,this.socket,event); + + line = br.readLine(); + } + + } catch (SocketTimeoutException ste) { + timeout = true; + + } catch (SocketException se) { + AbstractSyslogServer.handleException(this.sessions,this.server,this.socket.getRemoteSocketAddress(),se); + + if ("Socket closed".equals(se.getMessage())) { + // + + } else { + // + } + + } catch (IOException ioe) { + AbstractSyslogServer.handleException(this.sessions,this.server,this.socket.getRemoteSocketAddress(),ioe); + } + + try { + AbstractSyslogServer.handleSessionClosed(this.sessions,this.server,this.socket,timeout); + + this.sessions.removeSocket(this.socket); + + this.socket.close(); + + } catch (IOException ioe) { + AbstractSyslogServer.handleException(this.sessions,this.server,this.socket.getRemoteSocketAddress(),ioe); + } + } + } + + protected ServerSocket serverSocket = null; + + protected final Sessions sessions = new Sessions(); + + protected TCPNetSyslogServerConfigIF tcpNetSyslogServerConfig = null; + + public void initialize() throws SyslogRuntimeException { + this.tcpNetSyslogServerConfig = null; + + try { + this.tcpNetSyslogServerConfig = (TCPNetSyslogServerConfigIF) this.syslogServerConfig; + + } catch (ClassCastException cce) { + throw new SyslogRuntimeException("config must be of type TCPNetSyslogServerConfig"); + } + + if (this.syslogServerConfig == null) { + throw new SyslogRuntimeException("config cannot be null"); + } + + if (this.tcpNetSyslogServerConfig.getBacklog() < 1) { + this.tcpNetSyslogServerConfig.setBacklog(SyslogConstants.SERVER_SOCKET_BACKLOG_DEFAULT); + } + } + + public Sessions getSessions() { + return this.sessions; + } + + public synchronized void shutdown() { + super.shutdown(); + + try { + if (this.serverSocket != null) { + if (this.syslogServerConfig.getShutdownWait() > 0) { + SyslogUtility.sleep(this.syslogServerConfig.getShutdownWait()); + } + + this.serverSocket.close(); + } + + synchronized(this.sessions) { + Iterator i = this.sessions.getSockets(); + + if (i != null) { + while(i.hasNext()) { + Socket s = (Socket) i.next(); + + s.close(); + } + } + } + + } catch (IOException ioe) { + // + } + + if (this.thread != null) { + this.thread.interrupt(); + this.thread = null; + } + } + + protected ServerSocketFactory getServerSocketFactory() throws IOException { + ServerSocketFactory serverSocketFactory = ServerSocketFactory.getDefault(); + + return serverSocketFactory; + } + + protected ServerSocket createServerSocket() throws IOException { + ServerSocket newServerSocket = null; + + ServerSocketFactory factory = getServerSocketFactory(); + + if (this.syslogServerConfig.getHost() != null) { + InetAddress inetAddress = InetAddress.getByName(this.syslogServerConfig.getHost()); + + newServerSocket = factory.createServerSocket(this.syslogServerConfig.getPort(),this.tcpNetSyslogServerConfig.getBacklog(),inetAddress); + + } else { + if (this.tcpNetSyslogServerConfig.getBacklog() < 1) { + newServerSocket = factory.createServerSocket(this.syslogServerConfig.getPort()); + + } else { + newServerSocket = factory.createServerSocket(this.syslogServerConfig.getPort(),this.tcpNetSyslogServerConfig.getBacklog()); + } + } + + return newServerSocket; + } + + public void run() { + try { + this.serverSocket = createServerSocket(); + this.shutdown = false; + + } catch (SocketException se) { + throw new SyslogRuntimeException(se); + + } catch (IOException ioe) { + throw new SyslogRuntimeException(ioe); + } + + handleInitialize(this); + + while(!this.shutdown) { + try { + Socket socket = this.serverSocket.accept(); + + if (this.tcpNetSyslogServerConfig.getTimeout() > 0) { + socket.setSoTimeout(this.tcpNetSyslogServerConfig.getTimeout()); + } + + if (this.tcpNetSyslogServerConfig.getMaxActiveSockets() > 0 && this.sessions.size() >= this.tcpNetSyslogServerConfig.getMaxActiveSockets()) { + if (this.tcpNetSyslogServerConfig.getMaxActiveSocketsBehavior() == TCPNetSyslogServerConfigIF.MAX_ACTIVE_SOCKETS_BEHAVIOR_REJECT) { + try { + socket.close(); + + } catch (Exception e) { + // + } + + socket = null; + + } else if (this.tcpNetSyslogServerConfig.getMaxActiveSocketsBehavior() == TCPNetSyslogServerConfigIF.MAX_ACTIVE_SOCKETS_BEHAVIOR_BLOCK) { + while (!this.shutdown && this.sessions.size() >= this.tcpNetSyslogServerConfig.getMaxActiveSockets() && socket.isConnected() && !socket.isClosed()) { + SyslogUtility.sleep(SyslogConstants.THREAD_LOOP_INTERVAL_DEFAULT); + } + } + } + + if (socket != null) { + TCPNetSyslogSocketHandler handler = new TCPNetSyslogSocketHandler(this.sessions,this,socket); + + Thread t = new Thread(handler); + + t.start(); + } + + } catch (SocketException se) { + if ("Socket closed".equals(se.getMessage())) { + this.shutdown = true; + + } else { + // + } + + } catch (IOException ioe) { + // + } + } + + handleDestroy(this); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfig.java b/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfig.java new file mode 100644 index 0000000..aabe4d9 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfig.java @@ -0,0 +1,86 @@ +package org.productivity.java.syslog4j.server.impl.net.tcp; + +import org.productivity.java.syslog4j.server.impl.net.AbstractNetSyslogServerConfig; + +/** +* TCPNetSyslogServerConfig provides configuration for TCPNetSyslogServer. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: TCPNetSyslogServerConfig.java,v 1.8 2010/11/28 01:38:08 cvs Exp $ +*/ +public class TCPNetSyslogServerConfig extends AbstractNetSyslogServerConfig implements TCPNetSyslogServerConfigIF { + private static final long serialVersionUID = -1546696301177599370L; + + protected int timeout = 0; + protected int backlog = 0; + protected int maxActiveSockets = TCP_MAX_ACTIVE_SOCKETS_DEFAULT; + protected byte maxActiveSocketsBehavior = TCP_MAX_ACTIVE_SOCKETS_BEHAVIOR_DEFAULT; + + public TCPNetSyslogServerConfig() { + // + } + + public TCPNetSyslogServerConfig(int port) { + this.port = port; + } + + public TCPNetSyslogServerConfig(int port, int backlog) { + this.port = port; + this.backlog = backlog; + } + + public TCPNetSyslogServerConfig(String host) { + this.host = host; + } + + public TCPNetSyslogServerConfig(String host, int port) { + this.host = host; + this.port = port; + } + + public TCPNetSyslogServerConfig(String host, int port, int backlog) { + this.host = host; + this.port = port; + this.backlog = backlog; + } + + public Class getSyslogServerClass() { + return TCPNetSyslogServer.class; + } + + public int getTimeout() { + return timeout; + } + + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + public int getBacklog() { + return this.backlog; + } + + public void setBacklog(int backlog) { + this.backlog = backlog; + } + + public int getMaxActiveSockets() { + return maxActiveSockets; + } + + public void setMaxActiveSockets(int maxActiveSockets) { + this.maxActiveSockets = maxActiveSockets; + } + + public byte getMaxActiveSocketsBehavior() { + return maxActiveSocketsBehavior; + } + + public void setMaxActiveSocketsBehavior(byte maxActiveSocketsBehavior) { + this.maxActiveSocketsBehavior = maxActiveSocketsBehavior; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfigIF.java b/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfigIF.java new file mode 100644 index 0000000..090d79b --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfigIF.java @@ -0,0 +1,30 @@ +package org.productivity.java.syslog4j.server.impl.net.tcp; + +import org.productivity.java.syslog4j.server.SyslogServerConfigIF; + +/** +* TCPNetSyslogServerConfigIF provides configuration for TCPNetSyslogServer. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: TCPNetSyslogServerConfigIF.java,v 1.3 2010/11/28 01:38:08 cvs Exp $ +*/ +public interface TCPNetSyslogServerConfigIF extends SyslogServerConfigIF { + public final static byte MAX_ACTIVE_SOCKETS_BEHAVIOR_BLOCK = 0; + public final static byte MAX_ACTIVE_SOCKETS_BEHAVIOR_REJECT = 1; + + public int getTimeout(); + public void setTimeout(int timeout); + + public int getBacklog(); + public void setBacklog(int backlog); + + public int getMaxActiveSockets(); + public void setMaxActiveSockets(int maxActiveSockets); + + public byte getMaxActiveSocketsBehavior(); + public void setMaxActiveSocketsBehavior(byte maxActiveSocketsBehavior); +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServer.java b/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServer.java new file mode 100644 index 0000000..7c45993 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServer.java @@ -0,0 +1,58 @@ +package org.productivity.java.syslog4j.server.impl.net.tcp.ssl; + +import java.io.IOException; + +import javax.net.ServerSocketFactory; +import javax.net.ssl.SSLServerSocketFactory; + +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.server.impl.net.tcp.TCPNetSyslogServer; + +/** +* SSLTCPNetSyslogServer provides a simple threaded TCP/IP server implementation +* which uses SSL/TLS. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SSLTCPNetSyslogServer.java,v 1.1 2009/03/29 17:38:58 cvs Exp $ +*/ +public class SSLTCPNetSyslogServer extends TCPNetSyslogServer { + public void initialize() throws SyslogRuntimeException { + super.initialize(); + + SSLTCPNetSyslogServerConfigIF sslTcpNetSyslogServerConfig = (SSLTCPNetSyslogServerConfigIF) this.tcpNetSyslogServerConfig; + + String keyStore = sslTcpNetSyslogServerConfig.getKeyStore(); + + if (keyStore != null && !"".equals(keyStore.trim())) { + System.setProperty("javax.net.ssl.keyStore",keyStore); + } + + String keyStorePassword = sslTcpNetSyslogServerConfig.getKeyStorePassword(); + + if (keyStorePassword != null && !"".equals(keyStorePassword.trim())) { + System.setProperty("javax.net.ssl.keyStorePassword",keyStorePassword); + } + + String trustStore = sslTcpNetSyslogServerConfig.getTrustStore(); + + if (trustStore != null && !"".equals(trustStore.trim())) { + System.setProperty("javax.net.ssl.trustStore",trustStore); + } + + String trustStorePassword = sslTcpNetSyslogServerConfig.getTrustStorePassword(); + + if (trustStorePassword != null && !"".equals(trustStorePassword.trim())) { + System.setProperty("javax.net.ssl.trustStorePassword",trustStorePassword); + } + } + + protected ServerSocketFactory getServerSocketFactory() throws IOException { + ServerSocketFactory serverSocketFactory = SSLServerSocketFactory.getDefault(); + + return serverSocketFactory; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServerConfig.java b/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServerConfig.java new file mode 100644 index 0000000..e0beb66 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServerConfig.java @@ -0,0 +1,59 @@ +package org.productivity.java.syslog4j.server.impl.net.tcp.ssl; + +import org.productivity.java.syslog4j.server.impl.net.tcp.TCPNetSyslogServerConfig; + +/** +* SSLTCPNetSyslogServerConfig provides configuration for SSLTCPNetSyslogServer. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SSLTCPNetSyslogServerConfig.java,v 1.1 2009/03/29 17:38:58 cvs Exp $ +*/ +public class SSLTCPNetSyslogServerConfig extends TCPNetSyslogServerConfig implements SSLTCPNetSyslogServerConfigIF { + private static final long serialVersionUID = -840102682868286462L; + + protected String keyStore = null; + protected String keyStorePassword = null; + + protected String trustStore = null; + protected String trustStorePassword = null; + + public String getKeyStore() { + return this.keyStore; + } + + public void setKeyStore(String keyStore) { + this.keyStore = keyStore; + } + + public String getKeyStorePassword() { + return this.keyStorePassword; + } + + public void setKeyStorePassword(String keyStorePassword) { + this.keyStorePassword = keyStorePassword; + } + + public String getTrustStore() { + return this.trustStore; + } + + public void setTrustStore(String trustStore) { + this.trustStore = trustStore; + } + + public String getTrustStorePassword() { + return this.trustStorePassword; + } + + public void setTrustStorePassword(String trustStorePassword) { + this.trustStorePassword = trustStorePassword; + } + + public Class getSyslogServerClass() { + return SSLTCPNetSyslogServer.class; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServerConfigIF.java b/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServerConfigIF.java new file mode 100644 index 0000000..cab8079 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServerConfigIF.java @@ -0,0 +1,27 @@ +package org.productivity.java.syslog4j.server.impl.net.tcp.ssl; + +import org.productivity.java.syslog4j.server.impl.net.tcp.TCPNetSyslogServerConfigIF; + +/** +* SSLTCPNetSyslogServerConfigIF provides configuration for SSLTCPNetSyslogServer. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SSLTCPNetSyslogServerConfigIF.java,v 1.1 2009/03/29 17:38:58 cvs Exp $ +*/ +public interface SSLTCPNetSyslogServerConfigIF extends TCPNetSyslogServerConfigIF { + public String getKeyStore(); + public void setKeyStore(String keyStore); + + public String getKeyStorePassword(); + public void setKeyStorePassword(String keyStorePassword); + + public String getTrustStore(); + public void setTrustStore(String trustStore); + + public String getTrustStorePassword(); + public void setTrustStorePassword(String trustStorePassword); +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServer.java b/src/main/java/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServer.java new file mode 100644 index 0000000..f5b803d --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServer.java @@ -0,0 +1,102 @@ +package org.productivity.java.syslog4j.server.impl.net.udp; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.net.UnknownHostException; + +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogRuntimeException; +import org.productivity.java.syslog4j.server.SyslogServerEventIF; +import org.productivity.java.syslog4j.server.impl.AbstractSyslogServer; +import org.productivity.java.syslog4j.util.SyslogUtility; + +/** +* UDPNetSyslogServer provides a simple non-threaded UDP/IP server implementation. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: UDPNetSyslogServer.java,v 1.16 2010/11/12 03:43:15 cvs Exp $ +*/ +public class UDPNetSyslogServer extends AbstractSyslogServer { + protected DatagramSocket ds = null; + + public void initialize() throws SyslogRuntimeException { + // + } + + public void shutdown() { + super.shutdown(); + + if (this.syslogServerConfig.getShutdownWait() > 0) { + SyslogUtility.sleep(this.syslogServerConfig.getShutdownWait()); + } + + if (this.ds != null && !this.ds.isClosed()) { + this.ds.close(); + } + } + + protected DatagramSocket createDatagramSocket() throws SocketException, UnknownHostException { + DatagramSocket datagramSocket = null; + + if (this.syslogServerConfig.getHost() != null) { + InetAddress inetAddress = InetAddress.getByName(this.syslogServerConfig.getHost()); + + datagramSocket = new DatagramSocket(this.syslogServerConfig.getPort(),inetAddress); + + } else { + datagramSocket = new DatagramSocket(this.syslogServerConfig.getPort()); + } + + return datagramSocket; + } + + public void run() { + try { + this.ds = createDatagramSocket(); + this.shutdown = false; + + } catch (SocketException se) { + return; + + } catch (UnknownHostException uhe) { + return; + } + + byte[] receiveData = new byte[SyslogConstants.SYSLOG_BUFFER_SIZE]; + + handleInitialize(this); + + while(!this.shutdown) { + DatagramPacket dp = null; + + try { + dp = new DatagramPacket(receiveData,receiveData.length); + + this.ds.receive(dp); + + SyslogServerEventIF event = createEvent(this.getConfig(),receiveData,dp.getLength(),dp.getAddress()); + + handleEvent(null,this,dp,event); + + } catch (SocketException se) { + int i = se.getMessage() == null ? -1 : se.getMessage().toLowerCase().indexOf("socket closed"); + + if (i == -1) { + handleException(null,this,dp.getSocketAddress(),se); + } + + } catch (IOException ioe) { + handleException(null,this,dp.getSocketAddress(),ioe); + } + } + + handleDestroy(this); + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServerConfig.java b/src/main/java/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServerConfig.java new file mode 100644 index 0000000..bd56c2f --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServerConfig.java @@ -0,0 +1,38 @@ +package org.productivity.java.syslog4j.server.impl.net.udp; + +import org.productivity.java.syslog4j.server.impl.net.AbstractNetSyslogServerConfig; + +/** +* UDPNetSyslogServerConfig provides configuration for UDPNetSyslogServer. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: UDPNetSyslogServerConfig.java,v 1.6 2010/10/28 05:10:57 cvs Exp $ +*/ +public class UDPNetSyslogServerConfig extends AbstractNetSyslogServerConfig { + private static final long serialVersionUID = -2005919161187055486L; + + public UDPNetSyslogServerConfig() { + // + } + + public UDPNetSyslogServerConfig(int port) { + this.port = port; + } + + public UDPNetSyslogServerConfig(String host) { + this.host = host; + } + + public UDPNetSyslogServerConfig(String host, int port) { + this.host = host; + this.port = port; + } + + public Class getSyslogServerClass() { + return UDPNetSyslogServer.class; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/util/Base64.java b/src/main/java/org/productivity/java/syslog4j/util/Base64.java new file mode 100644 index 0000000..cb385e5 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/util/Base64.java @@ -0,0 +1,1815 @@ +package org.productivity.java.syslog4j.util; + +/** + *

Encodes and decodes to and from Base64 notation.

+ *

Homepage: http://iharder.net/base64.

+ * + *

The options parameter, which appears in a few places, is used to pass + * several pieces of information to the encoder. In the "higher level" methods such as + * encodeBytes( bytes, options ) the options parameter can be used to indicate such + * things as first gzipping the bytes before encoding them, not inserting linefeeds + * (though that breaks strict Base64 compatibility), and encoding using the URL-safe + * and Ordered dialects.

+ * + *

The constants defined in Base64 can be OR-ed together to combine options, so you + * might make a call like this:

+ * + * String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DONT_BREAK_LINES ); + * + *

to compress the data before encoding it and then making the output have no newline characters.

+ * + * + *

+ * Change Log: + *

+ *
    + *
  • [Small code cleanup/fixes for inclusion into Syslog4j]
  • + *
  • v2.2.2 - Fixed encodeFileToFile and decodeFileToFile to use the + * Base64.InputStream class to encode and decode on the fly which uses + * less memory than encoding/decoding an entire file into memory before writing.
  • + *
  • v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug + * when using very small files (~< 40 bytes).
  • + *
  • v2.2 - Added some helper methods for encoding/decoding directly from + * one file to the next. Also added a main() method to support command line + * encoding/decoding from one file to the next. Also added these Base64 dialects: + *
      + *
    1. The default is RFC3548 format.
    2. + *
    3. Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates + * URL and file name friendly format as described in Section 4 of RFC3548. + * http://www.faqs.org/rfcs/rfc3548.html
    4. + *
    5. Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates + * URL and file name friendly format that preserves lexical ordering as described + * in http://www.faqs.org/qa/rfcc-1940.html
    6. + *
    + * Special thanks to Jim Kellerman at http://www.powerset.com/ + * for contributing the new Base64 dialects. + *
  • + * + *
  • v2.1 - Cleaned up javadoc comments and unused variables and methods. Added + * some convenience methods for reading and writing to and from files.
  • + *
  • v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems + * with other encodings (like EBCDIC).
  • + *
  • v2.0.1 - Fixed an error when decoding a single byte, that is, when the + * encoded data was a single byte.
  • + *
  • v2.0 - I got rid of methods that used booleans to set options. + * Now everything is more consolidated and cleaner. The code now detects + * when data that's being decoded is gzip-compressed and will decompress it + * automatically. Generally things are cleaner. You'll probably have to + * change some method calls that you were making to support the new + * options format (ints that you "OR" together).
  • + *
  • v1.5.1 - Fixed bug when decompressing and decoding to a + * byte[] using decode( String s, boolean gzipCompressed ). + * Added the ability to "suspend" encoding in the Output Stream so + * you can turn on and off the encoding if you need to embed base64 + * data in an otherwise "normal" stream (like an XML file).
  • + *
  • v1.5 - Output stream pases on flush() command but doesn't do anything itself. + * This helps when using GZIP streams. + * Added the ability to GZip-compress objects before encoding them.
  • + *
  • v1.4 - Added helper methods to read/write files.
  • + *
  • v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.
  • + *
  • v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream + * where last buffer being read, if not completely full, was not returned.
  • + *
  • v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.
  • + *
  • v1.3.3 - Fixed I/O streams which were totally messed up.
  • + *
+ * + *

+ * I am placing this code in the Public Domain. Do with it as you will. + * This software comes with no guarantees or warranties but with + * plenty of well-wishing instead! + * Please visit http://iharder.net/base64 + * periodically to check for updates or to contribute improvements. + *

+ * + * @author Robert Harder + * @author rob@iharder.net + * @version 2.2.2 + */ +public class Base64 +{ + +/* ******** P U B L I C F I E L D S ******** */ + + + /** No options specified. Value is zero. */ + public final static int NO_OPTIONS = 0; + + /** Specify encoding. */ + public final static int ENCODE = 1; + + + /** Specify decoding. */ + public final static int DECODE = 0; + + + /** Specify that data should be gzip-compressed. */ + public final static int GZIP = 2; + + + /** Don't break lines when encoding (violates strict Base64 specification) */ + public final static int DONT_BREAK_LINES = 8; + + /** + * Encode using Base64-like encoding that is URL- and Filename-safe as described + * in Section 4 of RFC3548: + * http://www.faqs.org/rfcs/rfc3548.html. + * It is important to note that data encoded this way is not officially valid Base64, + * or at the very least should not be called Base64 without also specifying that is + * was encoded using the URL- and Filename-safe dialect. + */ + public final static int URL_SAFE = 16; + + + /** + * Encode using the special "ordered" dialect of Base64 described here: + * http://www.faqs.org/qa/rfcc-1940.html. + */ + public final static int ORDERED = 32; + + +/* ******** P R I V A T E F I E L D S ******** */ + + + /** Maximum line length (76) of Base64 output. */ + private final static int MAX_LINE_LENGTH = 76; + + + /** The equals sign (=) as a byte. */ + private final static byte EQUALS_SIGN = (byte)'='; + + + /** The new line character (\n) as a byte. */ + private final static byte NEW_LINE = (byte)'\n'; + + + /** Preferred encoding. */ + private final static String PREFERRED_ENCODING = "UTF-8"; + + + // I think I end up not using the BAD_ENCODING indicator. + //private final static byte BAD_ENCODING = -9; // Indicates error in encoding + private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding + private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding + + +/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */ + + /** The 64 valid Base64 values. */ + //private final static byte[] ALPHABET; + /* Host platform me be something funny like EBCDIC, so we hardcode these values. */ + private final static byte[] _STANDARD_ALPHABET = + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', + (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/' + }; + + + /** + * Translates a Base64 value to either its 6-bit reconstruction value + * or a negative number indicating some other meaning. + **/ + private final static byte[] _STANDARD_DECODABET = + { + -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 + -5,-5, // Whitespace: Tab and Linefeed + -9,-9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 + -9,-9,-9,-9,-9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9,-9,-9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine + -9,-9,-9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9,-9,-9, // Decimal 62 - 64 + 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' + 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' + -9,-9,-9,-9,-9,-9, // Decimal 91 - 96 + 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' + 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' + -9,-9,-9,-9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + +/* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */ + + /** + * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548: + * http://www.faqs.org/rfcs/rfc3548.html. + * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash." + */ + private final static byte[] _URL_SAFE_ALPHABET = + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', + (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_' + }; + + /** + * Used in decoding URL- and Filename-safe dialects of Base64. + */ + private final static byte[] _URL_SAFE_DECODABET = + { + -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 + -5,-5, // Whitespace: Tab and Linefeed + -9,-9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 + -9,-9,-9,-9,-9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 + -9, // Plus sign at decimal 43 + -9, // Decimal 44 + 62, // Minus sign at decimal 45 + -9, // Decimal 46 + -9, // Slash at decimal 47 + 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine + -9,-9,-9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9,-9,-9, // Decimal 62 - 64 + 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' + 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' + -9,-9,-9,-9, // Decimal 91 - 94 + 63, // Underscore at decimal 95 + -9, // Decimal 96 + 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' + 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' + -9,-9,-9,-9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + + +/* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */ + + /** + * I don't get the point of this technique, but it is described here: + * http://www.faqs.org/qa/rfcc-1940.html. + */ + private final static byte[] _ORDERED_ALPHABET = + { + (byte)'-', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', + (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'_', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z' + }; + + /** + * Used in decoding the "ordered" dialect of Base64. + */ + private final static byte[] _ORDERED_DECODABET = + { + -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 + -5,-5, // Whitespace: Tab and Linefeed + -9,-9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 + -9,-9,-9,-9,-9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 + -9, // Plus sign at decimal 43 + -9, // Decimal 44 + 0, // Minus sign at decimal 45 + -9, // Decimal 46 + -9, // Slash at decimal 47 + 1,2,3,4,5,6,7,8,9,10, // Numbers zero through nine + -9,-9,-9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9,-9,-9, // Decimal 62 - 64 + 11,12,13,14,15,16,17,18,19,20,21,22,23, // Letters 'A' through 'M' + 24,25,26,27,28,29,30,31,32,33,34,35,36, // Letters 'N' through 'Z' + -9,-9,-9,-9, // Decimal 91 - 94 + 37, // Underscore at decimal 95 + -9, // Decimal 96 + 38,39,40,41,42,43,44,45,46,47,48,49,50, // Letters 'a' through 'm' + 51,52,53,54,55,56,57,58,59,60,61,62,63, // Letters 'n' through 'z' + -9,-9,-9,-9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + +/* ******** D E T E R M I N E W H I C H A L H A B E T ******** */ + + + /** + * Returns one of the _SOMETHING_ALPHABET byte arrays depending on + * the options specified. + * It's possible, though silly, to specify ORDERED and URLSAFE + * in which case one of them will be picked, though there is + * no guarantee as to which one will be picked. + */ + private final static byte[] getAlphabet( int options ) + { + if( (options & URL_SAFE) == URL_SAFE ) return _URL_SAFE_ALPHABET; + else if( (options & ORDERED) == ORDERED ) return _ORDERED_ALPHABET; + else return _STANDARD_ALPHABET; + + } // end getAlphabet + + + /** + * Returns one of the _SOMETHING_DECODABET byte arrays depending on + * the options specified. + * It's possible, though silly, to specify ORDERED and URL_SAFE + * in which case one of them will be picked, though there is + * no guarantee as to which one will be picked. + */ + private final static byte[] getDecodabet( int options ) + { + if( (options & URL_SAFE) == URL_SAFE ) return _URL_SAFE_DECODABET; + else if( (options & ORDERED) == ORDERED ) return _ORDERED_DECODABET; + else return _STANDARD_DECODABET; + + } // end getAlphabet + + + + /** Defeats instantiation. */ + private Base64(){} + + + /** + * Encodes or decodes two files from the command line; + * feel free to delete this method (in fact you probably should) + * if you're embedding this code into a larger program. + */ + public final static void main( String[] args ) + { + if( args.length < 3 ){ + usage("Not enough arguments."); + } // end if: args.length < 3 + else { + String flag = args[0]; + String infile = args[1]; + String outfile = args[2]; + if( flag.equals( "-e" ) ){ + Base64.encodeFileToFile( infile, outfile ); + } // end if: encode + else if( flag.equals( "-d" ) ) { + Base64.decodeFileToFile( infile, outfile ); + } // end else if: decode + else { + usage( "Unknown flag: " + flag ); + } // end else + } // end else + } // end main + + /** + * Prints command line usage. + * + * @param msg A message to include with usage info. + */ + private final static void usage( String msg ) + { + System.err.println( msg ); + System.err.println( "Usage: java Base64 -e|-d inputfile outputfile" ); + } // end usage + + +/* ******** E N C O D I N G M E T H O D S ******** */ + + + /** + * Encodes up to the first three bytes of array threeBytes + * and returns a four-byte array in Base64 notation. + * The actual number of significant bytes in your array is + * given by numSigBytes. + * The array threeBytes needs only be as big as + * numSigBytes. + * Code can reuse a byte array by passing a four-byte array as b4. + * + * @param b4 A reusable byte array to reduce array instantiation + * @param threeBytes the array to convert + * @param numSigBytes the number of significant bytes in your array + * @return four byte array in Base64 notation. + * @since 1.5.1 + */ + private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options ) + { + encode3to4( threeBytes, 0, numSigBytes, b4, 0, options ); + return b4; + } // end encode3to4 + + + /** + *

Encodes up to three bytes of the array source + * and writes the resulting four Base64 bytes to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 3 for + * the source array or destOffset + 4 for + * the destination array. + * The actual number of significant bytes in your array is + * given by numSigBytes.

+ *

This is the lowest level of the encoding methods with + * all possible parameters.

+ * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param numSigBytes the number of significant bytes in your array + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @return the destination array + * @since 1.3 + */ + private static byte[] encode3to4( + byte[] source, int srcOffset, int numSigBytes, + byte[] destination, int destOffset, int options ) + { + byte[] ALPHABET = getAlphabet( options ); + + // 1 2 3 + // 01234567890123456789012345678901 Bit position + // --------000000001111111122222222 Array position from threeBytes + // --------| || || || | Six bit groups to index ALPHABET + // >>18 >>12 >> 6 >> 0 Right shift necessary + // 0x3f 0x3f 0x3f Additional AND + + // Create buffer with zero-padding if there are only one or two + // significant bytes passed in the array. + // We have to shift left 24 in order to flush out the 1's that appear + // when Java treats a value as negative that is cast from a byte to an int. + int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 ) + | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 ) + | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 ); + + switch( numSigBytes ) + { + case 3: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; + destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ]; + return destination; + + case 2: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; + destination[ destOffset + 3 ] = EQUALS_SIGN; + return destination; + + case 1: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = EQUALS_SIGN; + destination[ destOffset + 3 ] = EQUALS_SIGN; + return destination; + + default: + return destination; + } // end switch + } // end encode3to4 + + + + /** + * Serializes an object and returns the Base64-encoded + * version of that serialized object. If the object + * cannot be serialized or there is another error, + * the method will return null. + * The object is not GZip-compressed before being encoded. + * + * @param serializableObject The object to encode + * @return The Base64-encoded object + * @since 1.4 + */ + public static String encodeObject( java.io.Serializable serializableObject ) + { + return encodeObject( serializableObject, NO_OPTIONS ); + } // end encodeObject + + + + /** + * Serializes an object and returns the Base64-encoded + * version of that serialized object. If the object + * cannot be serialized or there is another error, + * the method will return null. + *

+ * Valid options:

+     *   GZIP: gzip-compresses object before encoding it.
+     *   DONT_BREAK_LINES: don't break lines at 76 characters
+     *     Note: Technically, this makes your encoding non-compliant.
+     * 
+ *

+ * Example: encodeObject( myObj, Base64.GZIP ) or + *

+ * Example: encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES ) + * + * @param serializableObject The object to encode + * @param options Specified options + * @return The Base64-encoded object + * @see Base64#GZIP + * @see Base64#DONT_BREAK_LINES + * @since 2.0 + */ + public static String encodeObject( java.io.Serializable serializableObject, int options ) + { + // Streams + java.io.ByteArrayOutputStream baos = null; + java.io.OutputStream b64os = null; + java.io.ObjectOutputStream oos = null; + java.util.zip.GZIPOutputStream gzos = null; + + // Isolate options + int gzip = (options & GZIP); + + try + { + // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream + baos = new java.io.ByteArrayOutputStream(); + b64os = new Base64.OutputStream( baos, ENCODE | options ); + + // GZip? + if( gzip == GZIP ) + { + gzos = new java.util.zip.GZIPOutputStream( b64os ); + oos = new java.io.ObjectOutputStream( gzos ); + } // end if: gzip + else + oos = new java.io.ObjectOutputStream( b64os ); + + oos.writeObject( serializableObject ); + } // end try + catch( java.io.IOException e ) + { + e.printStackTrace(); + return null; + } // end catch + finally + { + try{ if (oos != null) oos.close(); } catch( Exception e ){} + try{ if (gzos != null) gzos.close(); } catch( Exception e ){} + try{ if (b64os != null) b64os.close(); } catch( Exception e ){} + try{ if (baos != null) baos.close(); } catch( Exception e ){} + } // end finally + + // Return value according to relevant encoding. + try + { + if (baos != null) { + return new String( baos.toByteArray(), PREFERRED_ENCODING ); + } + } // end try + catch (java.io.UnsupportedEncodingException uue) + { + if (baos != null) { + return new String( baos.toByteArray() ); + } + } // end catch + + return null; + } // end encode + + + + /** + * Encodes a byte array into Base64 notation. + * Does not GZip-compress data. + * + * @param source The data to convert + * @since 1.4 + */ + public static String encodeBytes( byte[] source ) + { + return encodeBytes( source, 0, source.length, NO_OPTIONS ); + } // end encodeBytes + + + + /** + * Encodes a byte array into Base64 notation. + *

+ * Valid options:

+     *   GZIP: gzip-compresses object before encoding it.
+     *   DONT_BREAK_LINES: don't break lines at 76 characters
+     *     Note: Technically, this makes your encoding non-compliant.
+     * 
+ *

+ * Example: encodeBytes( myData, Base64.GZIP ) or + *

+ * Example: encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES ) + * + * + * @param source The data to convert + * @param options Specified options + * @see Base64#GZIP + * @see Base64#DONT_BREAK_LINES + * @since 2.0 + */ + public static String encodeBytes( byte[] source, int options ) + { + return encodeBytes( source, 0, source.length, options ); + } // end encodeBytes + + + /** + * Encodes a byte array into Base64 notation. + * Does not GZip-compress data. + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @since 1.4 + */ + public static String encodeBytes( byte[] source, int off, int len ) + { + return encodeBytes( source, off, len, NO_OPTIONS ); + } // end encodeBytes + + + + /** + * Encodes a byte array into Base64 notation. + *

+ * Valid options:

+     *   GZIP: gzip-compresses object before encoding it.
+     *   DONT_BREAK_LINES: don't break lines at 76 characters
+     *     Note: Technically, this makes your encoding non-compliant.
+     * 
+ *

+ * Example: encodeBytes( myData, Base64.GZIP ) or + *

+ * Example: encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES ) + * + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @param options Specified options -- alphabet type is pulled from this (standard, url-safe, ordered) + * @see Base64#GZIP + * @see Base64#DONT_BREAK_LINES + * @since 2.0 + */ + public static String encodeBytes( byte[] source, int off, int len, int options ) + { + // Isolate options + int dontBreakLines = ( options & DONT_BREAK_LINES ); + int gzip = ( options & GZIP ); + + // Compress? + if( gzip == GZIP ) + { + java.io.ByteArrayOutputStream baos = null; + java.util.zip.GZIPOutputStream gzos = null; + Base64.OutputStream b64os = null; + + + try + { + // GZip -> Base64 -> ByteArray + baos = new java.io.ByteArrayOutputStream(); + b64os = new Base64.OutputStream( baos, ENCODE | options ); + gzos = new java.util.zip.GZIPOutputStream( b64os ); + + gzos.write( source, off, len ); + gzos.close(); + } // end try + catch( java.io.IOException e ) + { + e.printStackTrace(); + return null; + } // end catch + finally + { + try{ if (gzos != null) gzos.close(); } catch( Exception e ){} + try{ if (b64os != null) b64os.close(); } catch( Exception e ){} + try{ if (baos != null) baos.close(); } catch( Exception e ){} + } // end finally + + // Return value according to relevant encoding. + try + { + if (baos != null) { + return new String( baos.toByteArray(), PREFERRED_ENCODING ); + } + } // end try + catch (java.io.UnsupportedEncodingException uue) + { + if (baos != null) { + return new String( baos.toByteArray() ); + } + } // end catch + + return null; + } // end if: compress + + // Else, don't compress. Better not to use streams at all then. + else + { + // Convert option to boolean in way that code likes it. + boolean breakLines = dontBreakLines == 0; + + int len43 = len * 4 / 3; + byte[] outBuff = new byte[ ( len43 ) // Main 4:3 + + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding + + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines + int d = 0; + int e = 0; + int len2 = len - 2; + int lineLength = 0; + for( ; d < len2; d+=3, e+=4 ) + { + encode3to4( source, d+off, 3, outBuff, e, options ); + + lineLength += 4; + if( breakLines && lineLength == MAX_LINE_LENGTH ) + { + outBuff[e+4] = NEW_LINE; + e++; + lineLength = 0; + } // end if: end of line + } // en dfor: each piece of array + + if( d < len ) + { + encode3to4( source, d+off, len - d, outBuff, e, options ); + e += 4; + } // end if: some padding needed + + + // Return value according to relevant encoding. + try + { + return new String( outBuff, 0, e, PREFERRED_ENCODING ); + } // end try + catch (java.io.UnsupportedEncodingException uue) + { + return new String( outBuff, 0, e ); + } // end catch + + } // end else: don't compress + + } // end encodeBytes + + + + + +/* ******** D E C O D I N G M E T H O D S ******** */ + + + /** + * Decodes four bytes from array source + * and writes the resulting bytes (up to three of them) + * to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 4 for + * the source array or destOffset + 3 for + * the destination array. + * This method returns the actual number of bytes that + * were converted from the Base64 encoding. + *

This is the lowest level of the decoding methods with + * all possible parameters.

+ * + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @param options alphabet type is pulled from this (standard, url-safe, ordered) + * @return the number of decoded bytes converted + * @since 1.3 + */ + private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset, int options ) + { + byte[] DECODABET = getDecodabet( options ); + + // Example: Dk== + if( source[ srcOffset + 2] == EQUALS_SIGN ) + { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 ); + + destination[ destOffset ] = (byte)( outBuff >>> 16 ); + return 1; + } + + // Example: DkL= + else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) + { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) + | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 ); + + destination[ destOffset ] = (byte)( outBuff >>> 16 ); + destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 ); + return 2; + } + + // Example: DkLE + else + { + try{ + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) + // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) + | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6) + | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) ); + + + destination[ destOffset ] = (byte)( outBuff >> 16 ); + destination[ destOffset + 1 ] = (byte)( outBuff >> 8 ); + destination[ destOffset + 2 ] = (byte)( outBuff ); + + return 3; + }catch( Exception e){ + System.out.println(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) ); + System.out.println(""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) ); + System.out.println(""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) ); + System.out.println(""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) ); + return -1; + } // end catch + } + } // end decodeToBytes + + + + + /** + * Very low-level access to decoding ASCII characters in + * the form of a byte array. Does not support automatically + * gunzipping or any other "fancy" features. + * + * @param source The Base64 encoded data + * @param off The offset of where to begin decoding + * @param len The length of characters to decode + * @return decoded data + * @since 1.3 + */ + public static byte[] decode( byte[] source, int off, int len, int options ) + { + byte[] DECODABET = getDecodabet( options ); + + int len34 = len * 3 / 4; + byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output + int outBuffPosn = 0; + + byte[] b4 = new byte[4]; + int b4Posn = 0; + int i = 0; + byte sbiCrop = 0; + byte sbiDecode = 0; + for( i = off; i < off+len; i++ ) + { + sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits + sbiDecode = DECODABET[ sbiCrop ]; + + if( sbiDecode >= WHITE_SPACE_ENC ) // White space, Equals sign or better + { + if( sbiDecode >= EQUALS_SIGN_ENC ) + { + b4[ b4Posn++ ] = sbiCrop; + if( b4Posn > 3 ) + { + outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options ); + b4Posn = 0; + + // If that was the equals sign, break out of 'for' loop + if( sbiCrop == EQUALS_SIGN ) + break; + } // end if: quartet built + + } // end if: equals sign or better + + } // end if: white space, equals sign or better + else + { + System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" ); + return null; + } // end else: + } // each input character + + byte[] out = new byte[ outBuffPosn ]; + System.arraycopy( outBuff, 0, out, 0, outBuffPosn ); + return out; + } // end decode + + + + + /** + * Decodes data from Base64 notation, automatically + * detecting gzip-compressed data and decompressing it. + * + * @param s the string to decode + * @return the decoded data + * @since 1.4 + */ + public static byte[] decode( String s ) + { + return decode( s, NO_OPTIONS ); + } + + + /** + * Decodes data from Base64 notation, automatically + * detecting gzip-compressed data and decompressing it. + * + * @param s the string to decode + * @param options encode options such as URL_SAFE + * @return the decoded data + * @since 1.4 + */ + public static byte[] decode( String s, int options ) + { + byte[] bytes; + try + { + bytes = s.getBytes( PREFERRED_ENCODING ); + } // end try + catch( java.io.UnsupportedEncodingException uee ) + { + bytes = s.getBytes(); + } // end catch + // + + // Decode + bytes = decode( bytes, 0, bytes.length, options ); + + + // Check to see if it's gzip-compressed + // GZIP Magic Two-Byte Number: 0x8b1f (35615) + if( bytes != null && bytes.length >= 4 ) + { + + int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00); + if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head ) + { + java.io.ByteArrayInputStream bais = null; + java.util.zip.GZIPInputStream gzis = null; + java.io.ByteArrayOutputStream baos = null; + byte[] buffer = new byte[2048]; + int length = 0; + + try + { + baos = new java.io.ByteArrayOutputStream(); + bais = new java.io.ByteArrayInputStream( bytes ); + gzis = new java.util.zip.GZIPInputStream( bais ); + + while( ( length = gzis.read( buffer ) ) >= 0 ) + { + baos.write(buffer,0,length); + } // end while: reading input + + // No error? Get new bytes. + bytes = baos.toByteArray(); + + } // end try + catch( java.io.IOException e ) + { + // Just return originally-decoded bytes + } // end catch + finally + { + try{ if (baos != null) baos.close(); } catch( Exception e ){} + try{ if (gzis != null) gzis.close(); } catch( Exception e ){} + try{ if (bais != null) bais.close(); } catch( Exception e ){} + } // end finally + + } // end if: gzipped + } // end if: bytes.length >= 2 + + return bytes; + } // end decode + + + + + /** + * Attempts to decode Base64 data and deserialize a Java + * Object within. Returns null if there was an error. + * + * @param encodedObject The Base64 data to decode + * @return The decoded and deserialized object + * @since 1.5 + */ + public static Object decodeToObject( String encodedObject ) + { + // Decode and gunzip if necessary + byte[] objBytes = decode( encodedObject ); + + java.io.ByteArrayInputStream bais = null; + java.io.ObjectInputStream ois = null; + Object obj = null; + + try + { + bais = new java.io.ByteArrayInputStream( objBytes ); + ois = new java.io.ObjectInputStream( bais ); + + obj = ois.readObject(); + } // end try + catch( java.io.IOException e ) + { + e.printStackTrace(); + obj = null; + } // end catch + catch( java.lang.ClassNotFoundException e ) + { + e.printStackTrace(); + obj = null; + } // end catch + finally + { + try{ if (bais != null) bais.close(); } catch( Exception e ){} + try{ if (ois != null) ois.close(); } catch( Exception e ){} + } // end finally + + return obj; + } // end decodeObject + + + + /** + * Convenience method for encoding data to a file. + * + * @param dataToEncode byte array of data to encode in base64 form + * @param filename Filename for saving encoded data + * @return true if successful, false otherwise + * + * @since 2.1 + */ + public static boolean encodeToFile( byte[] dataToEncode, String filename ) + { + boolean success = false; + Base64.OutputStream bos = null; + try + { + bos = new Base64.OutputStream( + new java.io.FileOutputStream( filename ), Base64.ENCODE ); + bos.write( dataToEncode ); + success = true; + } // end try + catch( java.io.IOException e ) + { + + success = false; + } // end catch: IOException + finally + { + try{ if (bos != null) bos.close(); } catch( Exception e ){} + } // end finally + + return success; + } // end encodeToFile + + + /** + * Convenience method for decoding data to a file. + * + * @param dataToDecode Base64-encoded data as a string + * @param filename Filename for saving decoded data + * @return true if successful, false otherwise + * + * @since 2.1 + */ + public static boolean decodeToFile( String dataToDecode, String filename ) + { + boolean success = false; + Base64.OutputStream bos = null; + try + { + bos = new Base64.OutputStream( + new java.io.FileOutputStream( filename ), Base64.DECODE ); + bos.write( dataToDecode.getBytes( PREFERRED_ENCODING ) ); + success = true; + } // end try + catch( java.io.IOException e ) + { + success = false; + } // end catch: IOException + finally + { + try{ if (bos != null) bos.close(); } catch( Exception e ){} + } // end finally + + return success; + } // end decodeToFile + + + + + /** + * Convenience method for reading a base64-encoded + * file and decoding it. + * + * @param filename Filename for reading encoded data + * @return decoded byte array or null if unsuccessful + * + * @since 2.1 + */ + public static byte[] decodeFromFile( String filename ) + { + byte[] decodedData = null; + Base64.InputStream bis = null; + try + { + // Set up some useful variables + java.io.File file = new java.io.File( filename ); + byte[] buffer = null; + int length = 0; + int numBytes = 0; + + // Check for size of file + if( file.length() > Integer.MAX_VALUE ) + { + System.err.println( "File is too big for this convenience method (" + file.length() + " bytes)." ); + return null; + } // end if: file too big for int index + buffer = new byte[ (int)file.length() ]; + + // Open a stream + bis = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream( file ) ), Base64.DECODE ); + + // Read until done + while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) + length += numBytes; + + // Save in a variable to return + decodedData = new byte[ length ]; + System.arraycopy( buffer, 0, decodedData, 0, length ); + + } // end try + catch( java.io.IOException e ) + { + System.err.println( "Error decoding from file " + filename ); + } // end catch: IOException + finally + { + try{ if (bis != null) bis.close(); } catch( Exception e) {} + } // end finally + + return decodedData; + } // end decodeFromFile + + + + /** + * Convenience method for reading a binary file + * and base64-encoding it. + * + * @param filename Filename for reading binary data + * @return base64-encoded string or null if unsuccessful + * + * @since 2.1 + */ + public static String encodeFromFile( String filename ) + { + String encodedData = null; + Base64.InputStream bis = null; + try + { + // Set up some useful variables + java.io.File file = new java.io.File( filename ); + byte[] buffer = new byte[ Math.max((int)(file.length() * 1.4),40) ]; // Need max() for math on small files (v2.2.1) + int length = 0; + int numBytes = 0; + + // Open a stream + bis = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream( file ) ), Base64.ENCODE ); + + // Read until done + while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) + length += numBytes; + + // Save in a variable to return + encodedData = new String( buffer, 0, length, Base64.PREFERRED_ENCODING ); + + } // end try + catch( java.io.IOException e ) + { + System.err.println( "Error encoding from file " + filename ); + } // end catch: IOException + finally + { + try{ if (bis != null) bis.close(); } catch( Exception e) {} + } // end finally + + return encodedData; + } // end encodeFromFile + + + + + /** + * Reads infile and encodes it to outfile. + * + * @param infile Input file + * @param outfile Output file + * @return true if the operation is successful + * @since 2.2 + */ + public static boolean encodeFileToFile( String infile, String outfile ) + { + boolean success = false; + java.io.InputStream in = null; + java.io.OutputStream out = null; + try{ + in = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream( infile ) ), + Base64.ENCODE ); + out = new java.io.BufferedOutputStream( new java.io.FileOutputStream( outfile ) ); + byte[] buffer = new byte[65536]; // 64K + int read = -1; + while( ( read = in.read(buffer) ) >= 0 ){ + out.write( buffer,0,read ); + } // end while: through file + success = true; + } catch( java.io.IOException exc ){ + exc.printStackTrace(); + } finally{ + try{ if (in != null) in.close(); } catch( Exception exc ){} + try{ if (out != null) out.close(); } catch( Exception exc ){} + } // end finally + + return success; + } // end encodeFileToFile + + + + /** + * Reads infile and decodes it to outfile. + * + * @param infile Input file + * @param outfile Output file + * @return true if the operation is successful + * @since 2.2 + */ + public static boolean decodeFileToFile( String infile, String outfile ) + { + boolean success = false; + java.io.InputStream in = null; + java.io.OutputStream out = null; + try{ + in = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream( infile ) ), + Base64.DECODE ); + out = new java.io.BufferedOutputStream( new java.io.FileOutputStream( outfile ) ); + byte[] buffer = new byte[65536]; // 64K + int read = -1; + while( ( read = in.read(buffer) ) >= 0 ){ + out.write( buffer,0,read ); + } // end while: through file + success = true; + } catch( java.io.IOException exc ){ + exc.printStackTrace(); + } finally{ + try{ if (in != null) in.close(); } catch( Exception exc ){} + try{ if (out != null) out.close(); } catch( Exception exc ){} + } // end finally + + return success; + } // end decodeFileToFile + + + /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */ + + + + /** + * A {@link Base64.InputStream} will read data from another + * java.io.InputStream, given in the constructor, + * and encode/decode to/from Base64 notation on the fly. + * + * @see Base64 + * @since 1.3 + */ + public static class InputStream extends java.io.FilterInputStream + { + private boolean encode; // Encoding or decoding + private int position; // Current position in the buffer + private byte[] buffer; // Small buffer holding converted data + private int bufferLength; // Length of buffer (3 or 4) + private int numSigBytes; // Number of meaningful bytes in the buffer + private int lineLength; + private boolean breakLines; // Break lines at less than 80 characters + private int options; // Record options used to create the stream. + private byte[] decodabet; // Local copies to avoid extra method calls + + + /** + * Constructs a {@link Base64.InputStream} in DECODE mode. + * + * @param in the java.io.InputStream from which to read data. + * @since 1.3 + */ + public InputStream( java.io.InputStream in ) + { + this( in, DECODE ); + } // end constructor + + + /** + * Constructs a {@link Base64.InputStream} in + * either ENCODE or DECODE mode. + *

+ * Valid options:

+         *   ENCODE or DECODE: Encode or Decode as data is read.
+         *   DONT_BREAK_LINES: don't break lines at 76 characters
+         *     (only meaningful when encoding)
+         *     Note: Technically, this makes your encoding non-compliant.
+         * 
+ *

+ * Example: new Base64.InputStream( in, Base64.DECODE ) + * + * + * @param in the java.io.InputStream from which to read data. + * @param options Specified options + * @see Base64#ENCODE + * @see Base64#DECODE + * @see Base64#DONT_BREAK_LINES + * @since 2.0 + */ + public InputStream( java.io.InputStream in, int options ) + { + super( in ); + this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES; + this.encode = (options & ENCODE) == ENCODE; + this.bufferLength = this.encode ? 4 : 3; + this.buffer = new byte[ this.bufferLength ]; + this.position = -1; + this.lineLength = 0; + this.options = options; // Record for later, mostly to determine which alphabet to use + this.decodabet = getDecodabet(options); + } // end constructor + + /** + * Reads enough of the input stream to convert + * to/from Base64 and returns the next byte. + * + * @return next byte + * @since 1.3 + */ + public int read() throws java.io.IOException + { + // Do we need to get data? + if( this.position < 0 ) + { + if( this.encode ) + { + byte[] b3 = new byte[3]; + int numBinaryBytes = 0; + for( int i = 0; i < 3; i++ ) + { + try + { + int b = this.in.read(); + + // If end of stream, b is -1. + if( b >= 0 ) + { + b3[i] = (byte)b; + numBinaryBytes++; + } // end if: not end of stream + + } // end try: read + catch( java.io.IOException e ) + { + // Only a problem if we got no data at all. + if( i == 0 ) + throw e; + + } // end catch + } // end for: each needed input byte + + if( numBinaryBytes > 0 ) + { + encode3to4( b3, 0, numBinaryBytes, this.buffer, 0, this.options ); + this.position = 0; + this.numSigBytes = 4; + } // end if: got data + else + { + return -1; + } // end else + } // end if: encoding + + // Else decoding + else + { + byte[] b4 = new byte[4]; + int i = 0; + for( i = 0; i < 4; i++ ) + { + // Read four "meaningful" bytes: + int b = 0; + do{ b = this.in.read(); } + while( b >= 0 && this.decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC ); + + if( b < 0 ) + break; // Reads a -1 if end of stream + + b4[i] = (byte)b; + } // end for: each needed input byte + + if( i == 4 ) + { + this.numSigBytes = decode4to3( b4, 0, this.buffer, 0, this.options ); + this.position = 0; + } // end if: got four characters + else if( i == 0 ){ + return -1; + } // end else if: also padded correctly + else + { + // Must have broken out from above. + throw new java.io.IOException( "Improperly padded Base64 input." ); + } // end + + } // end else: decode + } // end else: get data + + // Got data? + if( this.position >= 0 ) + { + // End of relevant data? + if( /*!encode &&*/ this.position >= this.numSigBytes ) + return -1; + + if( this.encode && this.breakLines && this.lineLength >= MAX_LINE_LENGTH ) + { + this.lineLength = 0; + return '\n'; + } // end if + else + { + this.lineLength++; // This isn't important when decoding + // but throwing an extra "if" seems + // just as wasteful. + + int b = this.buffer[ this.position++ ]; + + if( this.position >= this.bufferLength ) + this.position = -1; + + return b & 0xFF; // This is how you "cast" a byte that's + // intended to be unsigned. + } // end else + } // end if: position >= 0 + + // Else error + else + { + // When JDK1.4 is more accepted, use an assertion here. + throw new java.io.IOException( "Error in Base64 code reading stream." ); + } // end else + } // end read + + + /** + * Calls {@link #read()} repeatedly until the end of stream + * is reached or len bytes are read. + * Returns number of bytes read into array or -1 if + * end of stream is encountered. + * + * @param dest array to hold values + * @param off offset for array + * @param len max number of bytes to read into array + * @return bytes read into array or -1 if end of stream is encountered. + * @since 1.3 + */ + public int read( byte[] dest, int off, int len ) throws java.io.IOException + { + int i; + int b; + for( i = 0; i < len; i++ ) + { + b = read(); + + //if( b < 0 && i == 0 ) + // return -1; + + if( b >= 0 ) + dest[off + i] = (byte)b; + else if( i == 0 ) + return -1; + else + break; // Out of 'for' loop + } // end for: each byte read + return i; + } // end read + + } // end inner class InputStream + + + + + + + /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */ + + + + /** + * A {@link Base64.OutputStream} will write data to another + * java.io.OutputStream, given in the constructor, + * and encode/decode to/from Base64 notation on the fly. + * + * @see Base64 + * @since 1.3 + */ + public static class OutputStream extends java.io.FilterOutputStream + { + private boolean encode; + private int position; + private byte[] buffer; + private int bufferLength; + private int lineLength; + private boolean breakLines; + private byte[] b4; // Scratch used in a few places + private boolean suspendEncoding; + private int options; // Record for later + private byte[] decodabet; // Local copies to avoid extra method calls + + /** + * Constructs a {@link Base64.OutputStream} in ENCODE mode. + * + * @param out the java.io.OutputStream to which data will be written. + * @since 1.3 + */ + public OutputStream( java.io.OutputStream out ) + { + this( out, ENCODE ); + } // end constructor + + + /** + * Constructs a {@link Base64.OutputStream} in + * either ENCODE or DECODE mode. + *

+ * Valid options:

+         *   ENCODE or DECODE: Encode or Decode as data is read.
+         *   DONT_BREAK_LINES: don't break lines at 76 characters
+         *     (only meaningful when encoding)
+         *     Note: Technically, this makes your encoding non-compliant.
+         * 
+ *

+ * Example: new Base64.OutputStream( out, Base64.ENCODE ) + * + * @param out the java.io.OutputStream to which data will be written. + * @param options Specified options. + * @see Base64#ENCODE + * @see Base64#DECODE + * @see Base64#DONT_BREAK_LINES + * @since 1.3 + */ + public OutputStream( java.io.OutputStream out, int options ) + { + super( out ); + this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES; + this.encode = (options & ENCODE) == ENCODE; + this.bufferLength = this.encode ? 3 : 4; + this.buffer = new byte[ this.bufferLength ]; + this.position = 0; + this.lineLength = 0; + this.suspendEncoding = false; + this.b4 = new byte[4]; + this.options = options; + this.decodabet = getDecodabet(options); + } // end constructor + + + /** + * Writes the byte to the output stream after + * converting to/from Base64 notation. + * When encoding, bytes are buffered three + * at a time before the output stream actually + * gets a write() call. + * When decoding, bytes are buffered four + * at a time. + * + * @param theByte the byte to write + * @since 1.3 + */ + public void write(int theByte) throws java.io.IOException + { + // Encoding suspended? + if( this.suspendEncoding ) + { + super.out.write( theByte ); + return; + } // end if: supsended + + // Encode? + if( this.encode ) + { + this.buffer[ this.position++ ] = (byte)theByte; + if( this.position >= this.bufferLength ) // Enough to encode. + { + this.out.write( encode3to4( this.b4, this.buffer, this.bufferLength, this.options ) ); + + this.lineLength += 4; + if( this.breakLines && this.lineLength >= MAX_LINE_LENGTH ) + { + this.out.write( NEW_LINE ); + this.lineLength = 0; + } // end if: end of line + + this.position = 0; + } // end if: enough to output + } // end if: encoding + + // Else, Decoding + else + { + // Meaningful Base64 character? + if( this.decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC ) + { + this.buffer[ this.position++ ] = (byte)theByte; + if( this.position >= this.bufferLength ) // Enough to output. + { + int len = Base64.decode4to3( this.buffer, 0, this.b4, 0, this.options ); + this.out.write( this.b4, 0, len ); + //out.write( Base64.decode4to3( buffer ) ); + this.position = 0; + } // end if: enough to output + } // end if: meaningful base64 character + else if( this.decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC ) + { + throw new java.io.IOException( "Invalid character in Base64 data." ); + } // end else: not white space either + } // end else: decoding + } // end write + + + + /** + * Calls {@link #write(int)} repeatedly until len + * bytes are written. + * + * @param theBytes array from which to read bytes + * @param off offset for array + * @param len max number of bytes to read into array + * @since 1.3 + */ + public void write( byte[] theBytes, int off, int len ) throws java.io.IOException + { + // Encoding suspended? + if( this.suspendEncoding ) + { + super.out.write( theBytes, off, len ); + return; + } // end if: supsended + + for( int i = 0; i < len; i++ ) + { + write( theBytes[ off + i ] ); + } // end for: each byte written + + } // end write + + + + /** + * Method added by PHIL. [Thanks, PHIL. -Rob] + * This pads the buffer without closing the stream. + */ + public void flushBase64() throws java.io.IOException + { + if( this.position > 0 ) + { + if( this.encode ) + { + this.out.write( encode3to4( this.b4, this.buffer, this.position, this.options ) ); + this.position = 0; + } // end if: encoding + else + { + throw new java.io.IOException( "Base64 input not properly padded." ); + } // end else: decoding + } // end if: buffer partially full + + } // end flush + + + /** + * Flushes and closes (I think, in the superclass) the stream. + * + * @since 1.3 + */ + public void close() throws java.io.IOException + { + // 1. Ensure that pending characters are written + flushBase64(); + + // 2. Actually close the stream + // Base class both flushes and closes. + super.close(); + + this.buffer = null; + this.out = null; + } // end close + + + + /** + * Suspends encoding of the stream. + * May be helpful if you need to embed a piece of + * base640-encoded data in a stream. + * + * @since 1.5.1 + */ + public void suspendEncoding() throws java.io.IOException + { + flushBase64(); + this.suspendEncoding = true; + } // end suspendEncoding + + + /** + * Resumes encoding of the stream. + * May be helpful if you need to embed a piece of + * base640-encoded data in a stream. + * + * @since 1.5.1 + */ + public void resumeEncoding() + { + this.suspendEncoding = false; + } // end resumeEncoding + + + + } // end inner class OutputStream + + +} // end class Base64 diff --git a/src/main/java/org/productivity/java/syslog4j/util/OSDetectUtility.java b/src/main/java/org/productivity/java/syslog4j/util/OSDetectUtility.java new file mode 100644 index 0000000..f76145e --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/util/OSDetectUtility.java @@ -0,0 +1,77 @@ +package org.productivity.java.syslog4j.util; + +/** +* OSDetectUtility provides operating system detection used to determine +* whether Syslog4j is running on a Unix platform. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: OSDetectUtility.java,v 1.4 2008/11/14 04:31:59 cvs Exp $ +*/ +public final class OSDetectUtility { + private final static String[] UNIX_PLATFORMS = { + "Linux", + "Mac OS", + "Solaris", + "SunOS", + "MPE/iX", + "HP-UX", + "AIX", + "OS/390", + "FreeBSD", + "Irix", + "Digital Unix", + "FreeBSD", + "OSF1", + "OpenVMS" + }; + + private final static String[] WINDOWS_PLATFORMS = { + "Windows", + "OS/2" + }; + + private static boolean UNIX = false; + private static boolean WINDOWS = false; + + private OSDetectUtility() { + // + } + + private static boolean isMatch(String[] platforms) { + boolean match = false; + + String osName = System.getProperty("os.name"); + + if (osName != null && !"".equals(osName.trim())) { + osName = osName.toLowerCase(); + + for(int i=0; i -1) { + match = true; + break; + } + } + } + + return match; + } + + static { + UNIX = isMatch(UNIX_PLATFORMS); + WINDOWS = isMatch(WINDOWS_PLATFORMS); + } + + public static boolean isUnix() { + return UNIX; + } + + public static boolean isWindows() { + return WINDOWS; + } +} diff --git a/src/main/java/org/productivity/java/syslog4j/util/SyslogUtility.java b/src/main/java/org/productivity/java/syslog4j/util/SyslogUtility.java new file mode 100644 index 0000000..0ee5aa7 --- /dev/null +++ b/src/main/java/org/productivity/java/syslog4j/util/SyslogUtility.java @@ -0,0 +1,208 @@ +package org.productivity.java.syslog4j.util; + +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.productivity.java.syslog4j.SyslogCharSetIF; +import org.productivity.java.syslog4j.SyslogConstants; +import org.productivity.java.syslog4j.SyslogRuntimeException; + +/** +* SyslogUtility provides several common utility methods used within +* Syslog4j. +* +*

Syslog4j is licensed under the Lesser GNU Public License v2.1. A copy +* of the LGPL license is available in the META-INF folder in all +* distributions of Syslog4j and in the base directory of the "doc" ZIP.

+* +* @author <syslog4j@productivity.org> +* @version $Id: SyslogUtility.java,v 1.21 2010/11/28 01:38:08 cvs Exp $ +*/ +public final class SyslogUtility implements SyslogConstants { + private static final long serialVersionUID = 915031554586613648L; + + private SyslogUtility() { + // + } + + public static final InetAddress getInetAddress(String host) throws SyslogRuntimeException { + InetAddress address = null; + + try { + address = InetAddress.getByName(host); + + } catch (UnknownHostException uhe) { + throw new SyslogRuntimeException(uhe); + } + + return address; + } + + public static final String getFacilityString(int syslogFacility) { + switch(syslogFacility) { + case FACILITY_KERN: return "kern"; + case FACILITY_USER: return "user"; + case FACILITY_MAIL: return "mail"; + case FACILITY_DAEMON: return "daemon"; + case FACILITY_AUTH: return "auth"; + case FACILITY_SYSLOG: return "syslog"; + case FACILITY_LPR: return "lpr"; + case FACILITY_NEWS: return "news"; + case FACILITY_UUCP: return "uucp"; + case FACILITY_CRON: return "cron"; + case FACILITY_AUTHPRIV: return "authpriv"; + case FACILITY_FTP: return "ftp"; + case FACILITY_LOCAL0: return "local0"; + case FACILITY_LOCAL1: return "local1"; + case FACILITY_LOCAL2: return "local2"; + case FACILITY_LOCAL3: return "local3"; + case FACILITY_LOCAL4: return "local4"; + case FACILITY_LOCAL5: return "local5"; + case FACILITY_LOCAL6: return "local6"; + case FACILITY_LOCAL7: return "local7"; + + default: return "UNKNOWN"; + } + } + + public static final int getFacility(String facilityName) { + String _facilityName = facilityName; + + if (facilityName == null) { + return -1; + + } else { + _facilityName = facilityName.trim(); + } + + if("KERN".equalsIgnoreCase(_facilityName)) { return FACILITY_KERN; + } else if("USER".equalsIgnoreCase(facilityName)) { return FACILITY_USER; + } else if("MAIL".equalsIgnoreCase(facilityName)) { return FACILITY_MAIL; + } else if("DAEMON".equalsIgnoreCase(facilityName)) { return FACILITY_DAEMON; + } else if("AUTH".equalsIgnoreCase(facilityName)) { return FACILITY_AUTH; + } else if("SYSLOG".equalsIgnoreCase(facilityName)) { return FACILITY_SYSLOG; + } else if("LPR".equalsIgnoreCase(facilityName)) { return FACILITY_LPR; + } else if("NEWS".equalsIgnoreCase(facilityName)) { return FACILITY_NEWS; + } else if("UUCP".equalsIgnoreCase(facilityName)) { return FACILITY_UUCP; + } else if("CRON".equalsIgnoreCase(facilityName)) { return FACILITY_CRON; + } else if("AUTHPRIV".equalsIgnoreCase(facilityName)) { return FACILITY_AUTHPRIV; + } else if("FTP".equalsIgnoreCase(facilityName)) { return FACILITY_FTP; + } else if("LOCAL0".equalsIgnoreCase(facilityName)) { return FACILITY_LOCAL0; + } else if("LOCAL1".equalsIgnoreCase(facilityName)) { return FACILITY_LOCAL1; + } else if("LOCAL2".equalsIgnoreCase(facilityName)) { return FACILITY_LOCAL2; + } else if("LOCAL3".equalsIgnoreCase(facilityName)) { return FACILITY_LOCAL3; + } else if("LOCAL4".equalsIgnoreCase(facilityName)) { return FACILITY_LOCAL4; + } else if("LOCAL5".equalsIgnoreCase(facilityName)) { return FACILITY_LOCAL5; + } else if("LOCAL6".equalsIgnoreCase(facilityName)) { return FACILITY_LOCAL6; + } else if("LOCAL7".equalsIgnoreCase(facilityName)) { return FACILITY_LOCAL7; + } else { return -1; + } + } + + public static final int getLevel(String levelName) { + String _levelName = levelName; + + if (levelName == null) { + return -1; + + } else { + _levelName = levelName.trim(); + } + + if("DEBUG".equalsIgnoreCase(_levelName)) { return LEVEL_DEBUG; + } else if("INFO".equalsIgnoreCase(_levelName)) { return LEVEL_INFO; + } else if("NOTICE".equalsIgnoreCase(_levelName)) { return LEVEL_NOTICE; + } else if("WARN".equalsIgnoreCase(_levelName)) { return LEVEL_WARN; + } else if("ERROR".equalsIgnoreCase(_levelName)) { return LEVEL_ERROR; + } else if("CRITICAL".equalsIgnoreCase(_levelName)) { return LEVEL_CRITICAL; + } else if("ALERT".equalsIgnoreCase(_levelName)) { return LEVEL_ALERT; + } else if("EMERGENCY".equalsIgnoreCase(_levelName)) { return LEVEL_EMERGENCY; + } else { return -1; + } + } + + public static final boolean isClassExists(String className) { + try { + Class.forName(className); + return true; + + } catch (ClassNotFoundException cnfe) { + // + } + + return false; + } + + public static final String getLocalName() { + String localName = SEND_LOCAL_NAME_DEFAULT_VALUE; + + try { + InetAddress addr = InetAddress.getLocalHost(); + localName = addr.getHostName(); + + } catch (UnknownHostException uhe) { + // + } + + return localName; + } + + public static final byte[] getBytes(SyslogCharSetIF syslogCharSet, String data) { + byte[] dataBytes = null; + + try { + dataBytes = data.getBytes(syslogCharSet.getCharSet()); + + } catch (UnsupportedEncodingException uee) { + dataBytes = data.getBytes(); + } + + return dataBytes; + } + + public static final String newString(SyslogCharSetIF syslogCharSet, byte[] dataBytes) { + String data = newString(syslogCharSet,dataBytes,dataBytes.length); + + return data; + } + + public static final String newString(SyslogCharSetIF syslogCharSet, byte[] dataBytes, int dataLength) { + String data = null; + + try { + data = new String(dataBytes,0,dataLength,syslogCharSet.getCharSet()); + + } catch (UnsupportedEncodingException uee) { + data = new String(dataBytes); + } + + return data; + } + + public static final String getLevelString(int level) { + switch(level) { + case SyslogConstants.LEVEL_DEBUG: return "DEBUG"; + case SyslogConstants.LEVEL_INFO: return "INFO"; + case SyslogConstants.LEVEL_NOTICE: return "NOTICE"; + case SyslogConstants.LEVEL_WARN: return "WARN"; + case SyslogConstants.LEVEL_ERROR: return "ERROR"; + case SyslogConstants.LEVEL_CRITICAL: return "CRITICAL"; + case SyslogConstants.LEVEL_ALERT: return "ALERT"; + case SyslogConstants.LEVEL_EMERGENCY: return "EMERGENCY"; + + default: + return "UNKNOWN"; + } + } + + + public static void sleep(long duration) { + try { + Thread.sleep(duration); + + } catch (InterruptedException ie) { + // + } + } +} diff --git a/target/classes/org/productivity/java/syslog4j/Syslog.class b/target/classes/org/productivity/java/syslog4j/Syslog.class new file mode 100644 index 0000000000000000000000000000000000000000..ef637f11d34abbb36b75fa59937f8cc3851c776d GIT binary patch literal 6142 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 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/Syslog4jVersion.class b/target/classes/org/productivity/java/syslog4j/Syslog4jVersion.class new file mode 100644 index 0000000000000000000000000000000000000000..8ee117776585829fb0addbe321096dda0f276447 GIT binary patch literal 440 zcmb7A%SyvQ6g|^dYHe+;b>S{MAJDuELaVqb3PNbXNcPh-#0hbxB$Glv%a!255AdVJ zNvH_!+?;#PnVB>9-p{Z14*)ifJE-GO!%)K!ffn37`VWga!O%`y8|CXR z+Sns7{ufO!_?>&POrlT{oc`qNmN7BhE8Veddu-Wb=Tf)bsXLiEuAZ#7YMnK;O@QD8 x4K!74DOH1}7%BTv*invIX`p%W2J%{6*;m+7HgJHh!fwTz=qX(W_7&DJ_y#E@X%+wg literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/SyslogBackLogHandlerIF.class b/target/classes/org/productivity/java/syslog4j/SyslogBackLogHandlerIF.class new file mode 100644 index 0000000000000000000000000000000000000000..11b49ed3c95d47a16fa12640710accb98f7c9922 GIT binary patch literal 513 zcma)3O-sW-6r62iqxGwL^$%1K7eP-24?;r&0nvc>b+d$x>uyLk)%w#s_yhb=;!6rD z_L9?kZ+J7iGw<{3{R6-Sjzb)Vm@tgB)m{su-xR}edip@n{8g&bYiH{aM+`ycUM$1) zG;vkV%gSYq^m?iNiWg!jc)hBP%P$L_c1;}3k`6b*<~;S4w)w2p9W*7wS$~z5GbCk( zyZ)qj^X*NfbD6rPk}A@MjGwH(ek0^l;_`*CnNd|7owq(1u6p_YPiC0>#&G*sDCzr3 w-8a_jXZ3T35d+0XhXaCuLP0?DRy$E05fWmX28JDsySj_LzZ=x=)Aj%d-$hcD#{d8T literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/SyslogCharSetIF.class b/target/classes/org/productivity/java/syslog4j/SyslogCharSetIF.class new file mode 100644 index 0000000000000000000000000000000000000000..7cfed831e49bcbe71949bb6fadfee26896471466 GIT binary patch literal 259 zcmZXPK?=e!6htRltyTpWdWUw?Ah>fW2!h}u;6AM(ri4b)DCp5#cmNM2rbSS6@%b>k zKY!-&yxjrJFbWZc7=#!SL{hlrfmCu|~DR=6u+=VvZss^4H^yi9T{7JLT3X#_t8%Y_; igjHOtE6=p(5)icfw0*%=KoFn<_}xY56@p%^qyGZVtwp~8 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/SyslogConfigIF.class b/target/classes/org/productivity/java/syslog4j/SyslogConfigIF.class new file mode 100644 index 0000000000000000000000000000000000000000..8436b7858a0382e965595a91535306576adae293 GIT binary patch literal 1755 zcmbtVZBG+H5T1ofv7o%P2q*}?;Z=qD0=`hxDB5sI5o1vkzO8r5v3T7hw_5~%njicD z{wU+z-cb5NNE6efv(Gd0%o)*Ag4bDC%|bZ~Ygu^7;Bp{L?O2CVupV-) z8RVT}b)O&dQpiY7l#-J5M$7uxXp0iFmd z&f-T}!qW{OZH-K+FR#|_6L#LzS7Jf6fR zKcb9Pp#rmqorl5Q>^S%RuHz^>)hG^12XW-%eDV;xvSgc9+g4uQFQq-*A#^LY7bm3B zA~qdP25XM{Uuk1ej}A}v>9lvIQ~pgDcFc&k4Q~>5%NW-9mV4i;QLw?4A0{2Q+GC0B zI;yacR@m-iQ0}$BcHv3Vw2pQkc4V`>b`MsUt3{326BQX^=jQ2|iPWwP+{#jNUJMp{ zI>&VqF&I64o3_5~3lFdIQm-lSLMVgF>QRtB6>f#WN>4L0QV$xBvqHXtOYA?M29u9kOT~2g3m7S^xk5 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/SyslogConstants.class b/target/classes/org/productivity/java/syslog4j/SyslogConstants.class new file mode 100644 index 0000000000000000000000000000000000000000..ff9cc01722f1d0b291ee9b7f10c4d1cbb36cbd60 GIT binary patch literal 5778 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 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/SyslogMain.class b/target/classes/org/productivity/java/syslog4j/SyslogMain.class new file mode 100644 index 0000000000000000000000000000000000000000..52f8f44466b417c7d029c1ab0028bf187e0a37b9 GIT binary patch literal 5654 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 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/SyslogMessageIF.class b/target/classes/org/productivity/java/syslog4j/SyslogMessageIF.class new file mode 100644 index 0000000000000000000000000000000000000000..89572ff4d529bdb3dca22f8aa8864712b97907ca GIT binary patch literal 217 zcmZ9GK?=e!5Jmsg+Gs^^;URR>Ah>g15EK_ZL0Usd35}#_p&reJ2k=m0TLi(y44>h@ z|L667JOS*mV3;w?8Dhe+a8h`AmUS(ZB&;{vQz=@(ji?mQywjCB5aP@>u8^rVgD2~1 zW7U^ArpW*h66+MdIeTpiuUqXqJ_gmJd0+BBim>_>UGh>EzKO}y?^8$!F&z}5eg|M5#FsnD literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/SyslogMessageModifierConfigIF.class b/target/classes/org/productivity/java/syslog4j/SyslogMessageModifierConfigIF.class new file mode 100644 index 0000000000000000000000000000000000000000..43d31df1d03020a5b0ddaf06ed5022e798b17f91 GIT binary patch literal 405 zcma)&%Sr<=6o&s($EK~f3hfJY)ovODce)b>3YHcE?&CBQGYk_+GR3}{3m?FTl4eGw z3qi_(bAj*t=kodW{sG_y*9;d7mkd`7LqcDxuy!gpZ-miw_E^ZRN<6S4E9)l22Q)M{xrCO67G*eW-Ak; b_~IlXoT3{O0z7x$J8F)O=kAb-umAK;G?H?got zWAS*88Q#n=xBKM^V1aRnL5N|95g|D0gZi%sztgQYlAVk`oKvStscG};-xT+`1iC;&-R2tqR%E3k;(;O@-)~9Yq=D=I+qeA zj^?!)Vf9wL);Hnn753*Z6R9K2-_qLX!a80!8xRN`KOeroPM6R{5AZuc=n=wajidhn Dwa06L literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/SyslogMessageProcessorIF.class b/target/classes/org/productivity/java/syslog4j/SyslogMessageProcessorIF.class new file mode 100644 index 0000000000000000000000000000000000000000..426bf3661f69b9413ec442177631d5bfcfa44d23 GIT binary patch literal 327 zcmZ`#Jxc>Y5Pg%xoSqsa*xDx+E`nfTcS!KSVBor3HQ5Zyo<~;pHi7ulEc^lfC~6Vg$cm06yT%ZxBM6g#K|(!#C1mWi!}aJ6TiO4G2BnRhy7 z&gYYx9Y5jTd86LETdsAm8ymK&)z!3m?<)1*c+~ZKz{{c%9SD~#WSuI+TdwUpFKX!% c2%Tu%_?&K!(8CcBV;{*O9>)&hB>E20AL!Xyx&QzG literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/SyslogPoolConfigIF.class b/target/classes/org/productivity/java/syslog4j/SyslogPoolConfigIF.class new file mode 100644 index 0000000000000000000000000000000000000000..4e8c1b3cf1f8cdc2335786592e27ca015a68ba59 GIT binary patch literal 947 zcmah{*-pbS5L`o`Q0}Wx&XzNMAwuE@C<3WS9HNLyyoJ`Ju0o7rryQTg10TRgA=b`P zKtOp&teKq|uUGr}_WS|>J5b8NW(Kx0;4&BvxIXqD_Uc-+IfGueR6$aGBOSL=x@3?| zrIkjA!fYxbkXCBG&^F?zQ%@@>2 z$ze*ZiS~!4pD4{6W*a1Sh1*bOki&#u%Z^*Ndr_51T<3?_D1+JRqY7nkCS|xUqZ<)a z4!2u=+h?#N}whk*lq0C@I8#-0O&2MK3k$nwK5V$V^+V}!>^KSBCQ!c&B&Nk2pS n9L(CBImp{{p6~+UMZ!yjm&w0E{sI)OZxzIvQ9J&!geTR9ZODUS5lGHC`fU^ujucCE2i{m?OTBF)r_;lVWUl-nFy?fB+8 z^o<;evpYwO4b?rOIIi8j2>z=K!`jb^oq<-jQF7d}^27iAgdy8jp?1W%j2buQr|w2k zd1R4`Mw#K@U*#F<-<@Z_3>#RW-vp2gDWvJlkV;^YE~<$f%{*;RNGIq_Z|^*TJ;t5_ t&1}3a(Ys|Vk*Idupkr@C0 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/AbstractSyslog.class b/target/classes/org/productivity/java/syslog4j/impl/AbstractSyslog.class new file mode 100644 index 0000000000000000000000000000000000000000..4d4d64b1a7502f67b7597a61658d7dcb2f50baad GIT binary patch literal 11881 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 P83kzzMsJgWar^%PS#Sa> literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/AbstractSyslogConfigIF.class b/target/classes/org/productivity/java/syslog4j/impl/AbstractSyslogConfigIF.class new file mode 100644 index 0000000000000000000000000000000000000000..6000938ab62837b68c7cd00934d141d66a45f339 GIT binary patch literal 919 zcmah{O>fgc5S?w^22vnR(u6?yYWZ>wU?FjW6Dd@rN(3~8O6_TDPu&f!H`-l?mY>Ff zAHa`7jMtk4QV<7w^xnLA-W|UmKfiqkfM?*B;9&_KmEbXhwHVFdTqiQ#SHhs$O1Rbx z>VCU7CJjT9^#Idl_ zR{pV3A||a4#v$0^5J~*eSS7L$xI}_r2AaZ&hoQeAS9L5r+fVa|FnA$V9E_BV zve1YzZ6mPJ(Kc4khk-a9CBfev7_81>_U>qiA>HfAfBcHPP7blmfWZPiixlpLM^S<$ z0IJJSvh|Xym!WL&3S6=Es>9bDuE470t5CDG?(mw!4QN{aI<#!P0XJ=3hg-JZcKD9N Vcb)#8({DJunPWQdeR?mzgI^nK^2Y!G literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/AbstractSyslogWriter.class b/target/classes/org/productivity/java/syslog4j/impl/AbstractSyslogWriter.class new file mode 100644 index 0000000000000000000000000000000000000000..a065dc2798d5278bacd337e4dc1b8167d19e13c7 GIT binary patch literal 3422 zcmbVP`*Ryt75=WY);h}8Nu4;3Qxlv}T3NOu+@yIqgxYG-I>>HXCk~EF=~}v$Hd$#^ z?aEFRxj$-DzF(9j|hB{BZ?!O5wh&SMdY85=`4} zUAJw%e*4|&C;$C~Lc+i7yIxV@K+dZbGu4_`sOJM`!3i#BF4zlpCfYx6A>)**Zf11O z4{CNkm$)yXXy3Ps+NS}zkgXm#ZYJmW0na3YQcc?hh0bWtwJXKUnQ)D} zR-}Oj&O5Z@*ge=0@s6LQw06H#4+`F5g?^u>>SIpD363koQ~lElM%F86g)KR!q9^O+ zIbAzr&$(Rb%z1f6&1UR4Z!Q`^$)QI_@4=#TH7C$D+LILhOo(%ZS`MY|LDYyC9?$2= zzq=)VS=aXctnCLUF6DJKV6v&L!(Njgg|;v~j6-UCc1#4dxq3mn49>WMS&p)%5StxS z*yQUV%8Ei)szp^ZRl>fhWc$l!7*a;KZBbn1m})ARck6zMX|2^OS&x{}foAICoRa!A z3ByKFh|u*+y%IQO-RfWGTC`=o>Scy_%B$D%`lKU?>{*M@C=dGtk`_jA%wmZ@VqrfH zSa=i%EgZsO3rBF&#P=+GA3tEaKYbl6<4>VC1b+zd^$AjVbOYI+?6|_gd{`ZQ<+>mA zNg?X8uJEfukj>k9-M7~3WqZWsA6obkPAhD0Ez8P9U6A6m@MFAY;&lr@!D|+Nil3Qy z!@^bkT%mi_m8qcSRElGD$1Ug@Q8r;;dRoeUim2{OS@;EhDdbJ!qrZ=(o-gTwg|~3c z!mn`M#IG&<2B$6jR>%n6w(vVi#qaTsg{Se1g?I4>Ir>Knf5MW5KjSYJ&fu8B;SB=z z2~8zPdzkRie_50^@j@sjzc8SEA)dKD}nTU(`Vqe1+ju|Nn>c z zFCqpuFqo!!ivs9SVHc4T8JqLG>bP`|1)G-vJ2~G7ZN95@RYafapEmaJZPAYy(ilJj zyD*3$DD2}SDTWLT>7)EMq?LvvyJi_>BT1O=EJBD+prfq@gTm$9V?QC$1uv7!WgnmP1h0U zA8;f+AX?IYN2~$!1GH1g5*yfUBxgD|--LCCTWz;+pTaeCq;I2R<|ek#rW+L0MrAvw zI5K80pIyMiTupO*A9n`P&7kbT7f6Tc_WsbQJ}T~}KVYvUNuj`+;vhmkp3c_qJ%ow9Zd_baTdzJvQ^aqt#8V>q{j{hY-fknO?uvF$dt z)BLW^9SwA^ur#o}ueFp}R{+9yNyU_850=&_2Fe;ZnbgYB;tA{vdY`5d?=x zM^L1_KGPzB7awW!ie~}Faf%+v+Lw`|T!jftHhnzKxkMr%$uL&an+#V+>HkXv$D{3a6X0M#DKm|BR2qXc!IjUV~{Y!HEBjY9bdBJP4*>6(`-1U_;5BL+C0@ z5t%X`2}eV&9P%ifT}G@LA@&TeU1c~E*RX{HGx8b5%jzYSliAF~hk_dUyvYYzbl|fJ zgA8>0--(^2GJp*OfwusN}HyPIO#*p Xe0O01UtuedpkHlfP*I1Zd{5dO~6-IiJeR}hORAd0)IOGQDDH6&t!tgcG}f>ER7wA<8Tx81Z|5+21T z@KzHAqluSX_#VE7ar(2GxJ0}#O{X(+zM1*XoH_mWtcVn)Ob5jPnW-fEd{W8LI|=Q6No47oeDYllk=J%!>HgK*Dl zm<;_j+coR$rf&L=x$clBU-Jy^Y;oU??9?fQuk3)~LCy0mt>t@-wh`L9cDSeQ@LjG2 zdx7IwvpbsIY&n|Fjn`yqcl99jxe;!}tIOoAdDbd-8;QtRUFC3RQNl{&? zRBLfThr5=x5&E`kRk}UJZWrx8A<0nu=VA<5$J{j?YG9T4Hq9X5R@|a45|rOhn=Nhs z0*c!mXMeic#-mOWdBbb_hPh%#O`rH%uco7F3Qi%fpdSOoWV8OTzV@WfF#IQx<+klK zOkc#Tf;rq$FpmYIKd#_578x?*&&hhhu=>9al40OChc$i2G(v{CW3nGL5!DrjnPcMG zq3vi%@FuA=e+(xrGpt3Yl#BzzP@#JC03>&Up&z5>od zO|yI_q(nYmK7?3)i)_AUF{=uPkW?YDa$g`kJwSH!6LR|y^AZU)OJX0ri(=^mGH)=M zVpMX9c{xJF*b^O?D!!v48KMJ>AV*RqQX}+?(l}kf62|Zn7h|&P389oMQ6tp3cmtf! q=i{w$iWx&sL>%L!36yOU6QpGceV;OoQI&c6t4)$7QuL*`{^g$?GDVXB literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/backlog/NullSyslogBackLogHandler.class b/target/classes/org/productivity/java/syslog4j/impl/backlog/NullSyslogBackLogHandler.class new file mode 100644 index 0000000000000000000000000000000000000000..511e9bdbd2979b89a193ce0e7d2c5ab1e3025bf1 GIT binary patch literal 1170 zcmb_aQESss6#h<{E?rl3t6Fus*=-Is6@#!nbxd?x43vs=41ByzL%j7iDM?zH|4Muq zDEI^XQR2BtsDo722On~C?>XoD&Ue3ie*OOb6ToxqR#8UN!d4Xqn#;UwTiCJih){95 zz0;T7lQ)ERCyac19EF34o5-n5&h4R?3OhcJRp=iKZ8;h%yD!{Ne6+h0rFv=R6-PRu z|5gM8Zggbebtj{~7oCc};z+#{xJq_UR!Ga zH~#g8&$N3rETc+z{Xd4H1`8F!>fcv+*B^RrLO8sFe%^>VZEW!jm%)$2-#tyvbFTL+ znb#FQ+59K|mmgn%zVgOEEiVGraEr&fB7(Htn%QgZMhf5rYBb++;0=Q{OS}p+s4#ll=158SKm2HhHDod^`lhWxE z^bOj#=uCm8nQ5ng`%s;JD+vL{1!p{3X?H(;=bZ1d@<0Fn@h5=0kRuquY#76sHHLK2Fl)JnX;fPkOWjkg{oJm+C+D2~ncdu`ZCF^FX9!n~S9(#|Q#1xv zU=UgjcNSbwb=6vA7)llG*ELzMM~AVyts#{?#*q)2oIwwYw8aa8h?trh&=kf zqBJbk&?zE*J7>?k_gXkF`1}fo>Cv3L3U#H~lxqYZG+o^T6{B9Jyj33`Zv}WEFf4Y@ zqcfZ>xvg>hLQFnUTLXXRWTW63N_u}Wi9auQ9&X7n*^a?j=%5_DOo#(o&>YlBLFYtm3jf?maUx}E;*9=#k zsCZUVf}z)T#uG6oQ7hUr9?q3ZBzMs>4C`;>ES3=cZ=(me#miKUhxi+gv1f=xQMUF#!q|W7a(TF4iG$njYF`V zorS$guyLYw%Z8R5rylgU3r#@$z#&jhBJGlpY0hQGI+Ez1dAv;3u--6`A)qd%}LfUA{<{|5)5L z(sI1t7agS8q@%7)N5AcJmUPTv6$__wmiPGQJ^p!{D=*UfUXlJtym*l=cj7g5F|VNu cI4u#UWh~ME(vzND_BbuOoESbJY#%=S4{F1ErT_o{ literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/backlog/log4j/Log4jSyslogBackLogHandler.class b/target/classes/org/productivity/java/syslog4j/impl/backlog/log4j/Log4jSyslogBackLogHandler.class new file mode 100644 index 0000000000000000000000000000000000000000..0ed81a721cdf4f6da49ed4ac14951bc843677cd5 GIT binary patch literal 4353 zcmb_fTT@e46#g~@5<>7oy`i8H6-fZ2h=SlPC;@6j4R~*@C*g<(lbo0firQ9NtG&#$ zo%X4(ed$b}tW(kIO#9fG{-{pBz0V;DoS@QHX77En_d08R>syz7{Oj+RzXRBVFTB`_ zSRMQrufqh+%BOR3I`8FlK|Wn{LcPHhf%jue& zrrfyh#ahHXFyuO2j~hsOkdi;r@CiN^~dxvf(^i19`(^THFG~i1Tu}{ln z^z>v**K%fBKwJ`7(;ij!lUjNzbS$amasyJbp4Q2%+7MXnkP%qxd{Nn0us@#98tEye z(Q9cO(^86|l2KbmU|qRJdsnGEP~pHCnOw%OgC5Zmc{4k!%r;nN?Ja@rZ}Xx+|GzY; z@Oowb7+TV}LszTYC7%sbdY*CXnYMFmQ~PMZi9{VTs5MC|UBxJ~Os22EVJoz+NgOLd zMk51d!7Agw*2*ve%kJAKVu5AtRH-Ut1UlaygY>zY)C-(>`S&kDMjv+Kh!3sU=0?GX8SL<3yPVqO zbXcD4#vXxvvemqizE~lhH&S}BIt4Zo>U>H06IwcL=KXQqpDrYm()4~eZuxKk}ARj<#?-m(Q{-REj=3kMs7h3ea^v92+A)&T|z@UM^N$t4oOGQR2~Vr4?#iy~!f) zDi@zG)Yr(fkV@)pd8c@VF6b1B&SR)KJ~ViCm`!GMEOLr{XDAjs72_HSPlTf^f9t+j z3hQDxcGl3hoo|SZ6^79W^M?eUwv$WVMggaj0-n5SIV`Zd!WDNqYnWNyq~)FORD4=b zRyPXl}NU6cL)F46dJ#!y@;mG zMnj9TsnWWnq}xXGh|-dh?j_K4{E3EF@LX)Hdk*g(!HyTGcW~53WDnS-dkL(Ezm5}!EWHbi=4Bk@|8S1tN*U;IG2UUuSuzTQnGpx=QaNOUeo4?So<;r>=oUv| zcf&`mR~I4Ih&)c@I+0%^a)WrLi7Ux$NGbF|3r!Jyq=-IZqbF9Cx7GB3A64{6HlXA5 zL;Bbl{1sL6)UJ}$mfGG5$^aQQznfT%oU-S$-m>kLnw$FUusQmXtJFQQ@n_Cpf>{4# z6FtE(%yEq42*&_NFUMYv&{M2_@)V8ssOI`k*;vEp>L--5nzB{bGxY5iEBQ8KHcNKy zFs^s$-93!(qbtg9uG4r>hJ1qcBy9`I4B2>1awt9Rl3Z}OUSaLU=UCUcehwQtenXQ0 z9~w7u>g1Tira3g1X!5Gw`G}M}E=#DcVo16efMG>Q7eV!@gc`-WwsDQdW$z8x#%n4Y zZ&}jtmu$LUDZ|zk6et=F*oOHbNG7bfe}fuznYA>(z~+8lcFkQ)t~qS!ua)+jYMN>n z_|~Y>>uc2FTc*Hwyl1{wrba9!MN=(BA6pc`(xVo3hdxDYi}Kq=E$cDHbgrQ;AJd|b OJEas743!M-nSTH}t;N9r literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/backlog/printstream/PrintStreamSyslogBackLogHandler.class b/target/classes/org/productivity/java/syslog4j/impl/backlog/printstream/PrintStreamSyslogBackLogHandler.class new file mode 100644 index 0000000000000000000000000000000000000000..2c8dd043df28654b23409f84127499417faf3115 GIT binary patch literal 2553 zcmb_eYf~Fl7=BLfge|n8+$w3;^g;-ic%j-7q?S?yO(BK06ufnlY~$i)Hzpgj{s4b~ z;}`t{{p^f{(az{Mo$*IGK4&)#!Gr-FKjh?`_q^wMp7(N2^5IV{N8tuWq=;C2)tEQWC>iXLQov4p#Fwj9BG5v)Y9iudL4K?KRMS~FuSYmX=%ew=MK#ofj+HL(XC?Eu=J<8UK9{J z0-<@sGMoj0k!06n6ORM}ckH4r&@WG})ysLk`asK@w8XM@K{Fp|RYR_u#(?vgQ4`qC z+SO9JQnicqf@AC%&a<>DtM;sB+NIguv{9~@>AY6>oJ;yKfSMaXyXsBXd67<8yR@QN zMN_XblF{y3ccj=0$LzVAikE^7U8~uaKvc$VXr}QsgYhTj@#x*J3VOvcY>P1jiuRXu zTS%T1i>GsSIpgKf)T~mPLR|KX`FHFktGt&b1 zPk(5&leyC(k%Okbruhq1YY?y*w&a-EV_g-3}n|8fg(3cI_Jy+V=vsnAjrhq+O=9HXqa%E}ID<5dfqW!a9J*Hx=-nv#v- z47;7$R>j4-VHWjj7+VS+V_U%vK4gXF)TQ;UH35Y2k%Euq#wYlc#Zi;Y1$92bb{LEy zFHr+?>cgCZ0*VTBY1ld;fd6_!1XlhH^6fk?o>p+W)qt-_^FFm@!|mzu6DT~i)n&d; zCEdwYZO1OyY?1THiOwEkF1?#6Fx`!><3zI{d<)M0vsO$rZyw*lkp4woGkJ}Vgs`69 z)eBB$f^T2MvAs(wFyNvbeKOg~?z3d_2?#e^Ss?#^U!RWH7*xc%z8{}k8T>XB<@A%|(qxJq->{u;dn z^}o^7_n7Kr`>9>^4IayPgAIJs<@4H3ZSkp1K7lte+hq9;LAQC6smZbF(Le)3b3qdN zzem619St&~=TKhGhYzD0;z?j0y;xwTZ?P8_S-~ZjdBMYMF(+G*CYg)3+_;i>n=#7@ VB;Du(M2h1EZ9!_gNxKhoe*?7*OQ`?= literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/backlog/printstream/SystemErrSyslogBackLogHandler.class b/target/classes/org/productivity/java/syslog4j/impl/backlog/printstream/SystemErrSyslogBackLogHandler.class new file mode 100644 index 0000000000000000000000000000000000000000..5147ac22e0cef5fc8a65a7ad26608558f158c917 GIT binary patch literal 863 zcmbVKTWb?R7(J7$n`TWf);2LoFG-(LA6x`MN{bH>i^3veG^Kr;Y=-UB&CW8rDfC}y zUji-k2lPi3zZvr&5*x_NH}l=jIh>jMhnqV9uhA}H(*r}bj2d2ea8Wm*Q9_f!4YlC8 zU^wXP2TDhNs?~5D=JHbJSN;XRjSQuZ9G% z8puR^9*+h>f8&FgD(;a?Wd4q!*xBzhtOqLOai42x+S3^)KbIN9$vk#BN@IUOaxwa#^(=ixUFXb@S9qF=WcXF^OeGBLjKS-vu@1$tG+Or_#d&3{VE8`A zqQyj3@D!C2wkp`hj!AY+Xpt$4(tR=h^sGO#Twz$VPaE?jn)*j?B(!GO3~Wa#|1S)3 zvEG^4u+}#I)1xNZ^z&T$hd>c^l(0m3nX(oNwz_l+b~-`fCuQ^^6kR%jb&BK)MKk@D zwoSGC@)|{F0_PVc1v~Cppeg~^uuN66LW5YrDxC&oZ3@zbV`n`J(wyMQzbJLuYgm-( SpUEi-i0PS?#PHlQZ~O+gnA+3; literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/backlog/printstream/SystemOutSyslogBackLogHandler.class b/target/classes/org/productivity/java/syslog4j/impl/backlog/printstream/SystemOutSyslogBackLogHandler.class new file mode 100644 index 0000000000000000000000000000000000000000..79484a1432159910d47e9220e82806164e6b6a7e GIT binary patch literal 863 zcmbVK-AWrl7(J70H_4i68a0||HSsFxMHfL3QF>uPT3FiBSWCT|Y=$`LW+&{<27D{^ zCZOO0_)yYsrnx93t>Dc!^ZlK3I5Q8AxAy>c(JElo14FHZHLQDZQ8%Gczy^aGCW33h zaM11qDjE3WMD?>!%Zb#N{*X_&pI)Ys8te`IuDu-d@MoX~A9&o4MDp?EkimJc`UJ5Q z$XI;JMm>?7@?Jz0_ejQ4zhlU^J7)~lK!rRyiCQARI9(WMipQY2R>n(2Mo zHr3Lb8|0lSoNG#QcHFZ-H3DA4ORAa`8pI-&=rkae8OSjlJL_4HjVWIIjZ&w*hDE9U Ro}8h8m|j^)49k{zI6eex$jtx4G95nNL6dE`2D!|HzPCl)lu< z45{k$HbZ(Y^_L8w}trj`d% zA3A&dfIHD)JyhthWm zQ*ede5S$8Pr8|^~`k8cf$B56iy9h?#ho~ZHwxJ?TG2sW}vFhnQ@dny4+&=x4lr~f+ zY>IVhHZpc{lsTijgkg-7@Bot}w9^V0=1<}(()Cp+qKa;d%2YDdR3+dc-xpehb2-eF z;9#PJieXte|8g0goxiy8MtDLipCM1bR;#A+7$yuK4|uaJx<9lnynv3)sVkQrx}di_ z^f5^{nWvj&xP}6XinbYy6V$-2L3&-Of30 zp84XyK>#yUMF912 z#KR(f{5^mV@ef(qKLhv( zhlKEBY4}8P|MKBeA3pQpbA_UW6%U6ZYpr-99E+~0U!tIvDGXU0izbqxXmV{RlCp9d zZun^7wuVo(E954&BqFg^g^Gq)ytSqy9&1iDCBqxT$t^YOLmNXicKgirHI2GsecgP8 zoN%)hO)3N%beBjd+FH|?jEAGGY|M+qnnIBkp>|8bPkqT)Q!K)4OQ+~4=1fv7U8V~J0#<& zXj3R@r3We$rxF&I#yv^Jt>z`6WJn=D91SPA$>FVns!roBE|98Y6g=e>Yq_$;v1YEm zupu0^R;1e3S@G4ObrIGC8)R?RhIm9Qrz^e5wlL>ja<~Hsw|7KpcvhLSn7MvYM~4+{ zw&IN&tcaD2MY;WfUO0uJ_eZM+D% zA$>p!Q_3|>s3X+WW~C1?(Gjj`h_&(>w=Uht_cULwj<4Om-rVwtwb9}p!!kphhM;F~-};g4 z-{@{5MsmIZnua?@Wh}^W$Cyk*2}dmNXI)Czy?<@c?%UVw1nsVUD+}54)+q3r8Y9cYZD;!RdvSgh1o`(^YuFVn@`o3PMg;zXQeVig)q ztQN6G#99$2i#SEZsUl7jak_{zM4Tz&DvL->oD`U+f5S* zwD{B!rW&Kh`qVg6jVHb;RTF%w%v2NABvVaRQ%p6LhpNiK6RbVVM1yd6bTy)+k6m>- zMTO~ynJD9ZbcjTsSk!xXc3h)xWw@O!G*rBW^{vrZ+*%xx>samPGqW6^ts#9o>G=G~ zSdY^2{ovcINC#s#aSZ$y>mQHDc&8^1Y6-U8uh*eo6VVpBq76!w_M}q>*_BZr%}tN{ zp24VNPy_7&dZz0CYkdbKvhqCC+&tL?m!{iz zqle33^lxEg&IQjYh|31)z zFpMU4d42yz*&Fe)t8`#(HD|sAa#|v(M4NX4Kf>yvunZ;qbo??Jm|xCsS_3QK6|cy= zR~(~G=^J%Q_o!2PNS)G2>Xd#`r*xG%rMJ{69i~p{Gj&S0sZ)ARozi*gl>SqvbfG$> z7u6{pDbuNBqqC-LW$7g{(#_zk%6(9k>LC~+JR-azazx~c@QLt?$P*C|kuSm&F+@ax zh(ZxXB8o)>D?JaP3bMir)D26MAf zj`{qwJ`R;wifP>9Dy&2`1B~g6C5}Xx+Dv;1SdR_dXC>a5HBq*BnI6M-`cLL$!FQ3v zV0xx!L1i~i2@b97#IQ~b--*KDh;)7j{N4q7Fh4jlt8r9sqlb;-9>(ZX_u+`(m`;pk z)7aoRicXB*kJ2OV7mA$LC}cVUWd^LJx1+x+`6bz!E@m@bqX*n|A#Rh_8hBH5DX(4NQf;oyGb%YIgR;E8dSIyD&p{E$GHk>{!r=qi#gG zog3z4{gRV4=vZ)2Yn-Vy+S~IOX6?Yc)MpnT#jNEl1iCR^g9UoPimIeq51*}v=XXPP zJzoRKzA#6iqid@sbYYH1Hf=?9X4A}W6jzA~b3f*GVV+hoq^EL-uAHwc3%fCm{R*|- z33g5vdQ8>Wi@UJEskq3-D9T_km+sz$g?c|S7+$`~^jRLuv%HUYvk6;qE-D!8O;Ht0 zcd2{S{Y(!Tej^_h#w265F_#ZQR2Vy@sq z^#CqX2N;q+#)$j{Y*(+~GW8a&REKaCEy2}>AJ=h(*BB@`lp9s1o~P6M_9g-9aB9XSs^Y{VuQPhAajqR+#b({)_mtJuPwGdQ~s=iqB%FN{^T$wQ8@oIBb`JE6!R z#!pOLjV{AB4fkeDQZB23yR$53PFjt^`Ph~oEC)D%1vuv zfBEX84llp6zMj_g1Pzy$y6Sm{OLo$ebmBP4?!eq>omkX~TCp>WyD?f4RxMec;2Xx{w7O4VA)cgGGX?RIfyw=Z!$s$Az$y_7Y$_oyy)KdRhb1pBC7=4xLV;HV_>kd=JP6~yNRdCe7s z-@H^I7p~8p@i{?WC&(KEfJo>gAlqF*yiSleT|xN8>;~d>g1k)-u`Ph@b+a$8#AX6= zxhsg@3G$vR$QAA&ekaKL1o>b95D5YWxL58`4T<;EIIzdJeWb^1);;IihkF8h!bQ2LCOXI zk&h_>xzQD*zzH(h733y&kOC)21wkqY0Fkdb0lC=~q|gac?Fw>>J4m4uWClTw8URE- zCk5pDt{_EDkXf!Ex4MHAIYH(UWZnQE@;xgcKX3&pc7iN)1=;NmQtSj-M3CA6K;(m3 kKz`^75_Ezrbp_eu4ia>N)DvXc03h;3FCcqqdkoz6Kk%)!M+>7y&ygc;bW|e<&yxEAT~k>qaqenEIfeC z5XObms@S*0qKRc&i0=oW2T%*ZU>Iw1Q&aRcZZ@^Lv6^3CVAmKTnYz)m6vJ9m^cMH~ zf6x4N?9acyWjL_9w2;l^m$IZ7Eo>`0imWR}RW4bkW>n`H4wE>&S}3nCq|4d$-115> zUGCzR^TiJLkf)n1v6eAJa`hWMUvC3~Zg&ScjYI!eQrHAAzmF!*K?YYbAR zu5yNh1l-)mFvQb~I~Ow##Ym zHuZY-!nUl{8oFHL&8AZ2a(bg_nM%bf+0vrJrE%#~`$qkt zAvCg&D!gG4;;4lYU0hPfZp3Km`m&j=HLP8RaX0yHlqK#k_;&;{3BYDwqpuGz>904_ z&l-3?2R1dXt4>KF`)tnyje^>__lUtC=7gRri&RWbopW)*5GvJMW`*Z8fy&8&U^*+% z7e*3iXb9HHWS4$&u_&u5LvV31RjZ|%gxg6Qr51l=$t3|%8y60E!gw2V!bP27)K>GZ zJd6e&gmDRT)G}Mt)ljOXWvG0U#zzgn45JAvjF!-yvUT^nJqCJCc0|mFcofDiK4m!C z>-}m=(^WAX>|Pk3;d8Nk5yqFo>??fDkpAC;_(Dy~8{51>gLL*KZeJMXd~P48(epCA z>5k^f{z2*o5yKI$XL)K|T2)PYE}W;r8xe+yz2`tQw@Z;GVuYT6&OAu;wALsK{-CAk zJoW@pclOe{ z&Twf!nEvkcd!Cn0(06SL46kAslQ@oPI-j7Azz|+T94B$gqa#GW-bMR}exr+)h@L^h z(?3o0Y?pk9;L5~^(R!95$g~rN;XnNp>?b>7-&j!-Dm3SH9a%Xlt#YKRO&T7KhX3Y z&-4a-R3I?%4F21v+ZcX|z%vAIKgEGILWS9mzmTnW5ixp;&XGmTv2&XssFZyn66W{y zKJpUp^W^p2eY{_Gy}yeqZrLrmJ@KDn*8eNQ#iXyRgjq_yl$2bK2TM;q!gcA0oS}UV)n=5h;vCBZZ$a+NQrMKR_x{+XO#^ z2*$`l;3q~NfNR7p68|PimNANw7ju-P8OlRk#+V!3M_O68>>NID%f3cBLMt}=90#L^ zsIX`ohrdHWqR_rx#NO&^XUwZAhDFzJo^o4>E1ddqrXd4q#ZN%G{6soVJ{BeJ8ckj~F-=jBRogkywd0cTKczL97-Ohue lqCh86SBg56u)CTj`>;eOzr?6(bELy?gVrJ3{1-)Qc=-ST literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifier.class b/target/classes/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifier.class new file mode 100644 index 0000000000000000000000000000000000000000..c196000df1183a1c1d1cd9d183f39fcd38c55c38 GIT binary patch literal 2066 zcmbtV-%}e^6#j0qn-EwEh6bFrw3Mn%Hfd83=?@@Esn{(6YC}=%jN=kE>0+|M-3?Rx zCwyjn@WmNl`cP*oRcGvDANse{S05d}yBnx2J2F!zGv}Uj?m6e)@0{;$p8x&(QvhRF z>&5^kQb^;29!%o06j!=wUhTrQZuDSEis>%Q$hDNjhjRT$idiYHOED)CZbO1x zUlN$j{=ZVWRRLwLwP6YLm2JmbYB$#{cg0+9(338=szhrNGwqI3@$cK7z{*kQ+Rd#- zv4g+Z>@=V_yYBg}S@k0U64=0&>3WvoGI+OB zaZV)fjCp~0Rz8L4H%Sj)wJegVTmJ113yx=VhvycCR66`n$mAyZVtvy#8+=o*Of*C^ zB`4a`Fg@RJHmnEBwb!Ed9|K94^4juo@ofkUW(_0q_(a2U>i+!zFLN^4=&->EZW%d4 zIm-{?00fRBM#5w;NPUQ3-5B16A}K^&rSBAmDNoZ{=3b0zpZ)|w7r!8;=P7;;lFm@3 znFxMy6{Psna16Z|p=U5m!&!{dVu7GMIVf4xDZYSs5H*z7A0ze~;sT+f2>c555z}Ij zha{K)^#7~y&_UrLyo>j^pOS!U-{|s6>kq^v7 zI#n(Nb|J7Y>GXF`Dj6mABSzFe(6biT;~8ZST4hbqGYYqRzuLpG%F<6L=}g)W9@FzO ztZ!1ysLUNb$W`}q)gU*lwRGVnxa$OlU?hX=<`A_L1b32MI?cbsGq^&l#4g?=&@Tzq zLKa^m2OoKSivo5THNpxvk!0*S?&dfRpV3lN89xC%@UbC5vlvV*AGA$s1!{84ySRXh zh%1VG^o$W)$HJDP&YE%hhGmEP7umE_;i>uq)c8Za5Faln<9m4PAp^pRg|xWLDO@GI eYXmkETyi8VaxlH&&h!!lE)S3KxbdLM`~Lu?SMPHG literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifierConfig.class b/target/classes/org/productivity/java/syslog4j/impl/message/modifier/AbstractSyslogMessageModifierConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..0cbd781d2dc7bde3802db83e58870514fc22d1e5 GIT binary patch literal 1361 zcmcIjO>YuW6g>|Z29VljT3W4I`=J$vwjFw@Kojg4{P z)}4v}!L23|6Blkx{2%@e<9)-FHi)$wH}AgtdG5LQy&u26eglxh-2@W26+=3XI5IKl zQf6aVk#aSLH5G=6+bVJ@?l4Ta+!1EG!W~!G*539*2DZa6mbWd}GcB)Tw!2(;^z+SI z<;A=A4ABFJH^fT@t=KXTO`~mEO{45N!fM_puiI_-UbVJwI%V#WX;WCj+hPc(GZltN z-mY_o@uIN!<8G(Qon5oqCW}_IYt)BH-H;v_Bi_Dn8J-tyr)eBGcD-Bk#G&wx3?JM* za@%%uy=92bLEGqX*EO5m=-7495Zo~yR9(+8YhKw8EA`!_z)J)hLiQYQa_?zCYAT%> zMN5X117>meBs`V=Gg^|AF~{)<%FQ1SBSDT6rEGVd8ZQV*KYfm7*CgpArZK}1ntzpq zhDlo2>m;V+McLaetZpQck_s4}{jZ_Xt2x>IlWL3CXwRGfKs#dz+XaTTbEOBf+b%>F z=rt!0!UZG|!7RpbktmPT7YJd3EHoOrN91IDNkbv2QVflc&P$|~D3&IL8T|{Gu7!FC z>sq7-Mc1M|sGrCc!eu%&D%3wy1UgLsGXx2O_S10%S4m^IhPj}$K~nk@{WHQJ>C!J0 z^^LQql9fU7^^wWSaPr*9C7Rqa5ls7K zr~9cvPgKO8qolHU27nR(D8m3*0$3pcgUaOo0w5P80hUJ6SBL4ZkEDNN(A`!*KPnlY cTA_R^zy=iDJJm>Zz%(kqjo-*ke_PAH0ct-C2LJ#7 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/modifier/checksum/ChecksumSyslogMessageModifier.class b/target/classes/org/productivity/java/syslog4j/impl/message/modifier/checksum/ChecksumSyslogMessageModifier.class new file mode 100644 index 0000000000000000000000000000000000000000..f4bcd776255195c4f13c66b782aa812057db0700 GIT binary patch literal 3980 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 I6;{;#05U8~XaE2J literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/modifier/escape/HTMLEntityEscapeSyslogMessageModifier.class b/target/classes/org/productivity/java/syslog4j/impl/message/modifier/escape/HTMLEntityEscapeSyslogMessageModifier.class new file mode 100644 index 0000000000000000000000000000000000000000..11b737974919191ae2c2a235bdb0a672e9d37020 GIT binary patch literal 2201 zcmcIl-*XdH6#j0SA4}Xq3{XjF1OY?ZB2j@V6bfzH+LV+Eg;r41?e-?!y2*y!O-Ejw zadbw;SD&gcsN?j78F9u5j5t2{U}yZJ)bH+QS|K>}#dh}YIcLxL?sw1q?#-Wn{qh@t z*We`4i}MLwNFsvs8b*^CLs1RmDl(D4q;lR$Lc^4@N*bn>b5TQC!;FSY8fI1C?IbSa ziiSDmT-9(*`SWU6P?2{MxSqfbfs`j*%dqFA>se0yT4`KBObc`uox0~6b${Nln=cjYXT0blEWpYY?1%I~ets zEl07Iof4i_^tQrOHwr4xllPd+Q*02jT>3K#~7HZCtRk5U7ke+EY zWMS&+OnIX2vuYv;%mr05VfIWrd6-KuU1|7oTvm*x?F*dA_djdir$Ut`2^J4n+!nZ; z-yR67N~LnJEZeA83v<3})vLq(ogsmp;mVfUYf#PWC?tijJp$WYM!;LE7^Y>jSKQW; zK+Kk_(iTXxn@iMH?tg`!_vSk%?WaJJA-O5P#=6|ok~-@IBIYt@Eb_7VEDG%F$Qo-_ zD$-?dlXFhfHRYtGbThE6?LDsgqvItU5-|REF$o}ncXhmnn>yad2RerEhCt7gn-s1{ z$A<{GE$T3_#50n!{b3yv6=hd_C8yl2rlX8l?(m7z!P}@cf~0B!%Q`Hqu!*_Ds_Y|n zke_U<=%}foj+;EVTeHtDu1J##A9_Y7{zKl6VTC#+QR=lOu!o0cYofM@$zR@T8a9ve zW2y;x3@g>dZCS7S)Bvvu>MoiusoNrME*tJBnJS;+h#QTDtg}VOwxz30#q7@)J85lx z-MvM)$oUM@m#%Gy87c5hEg?4W0OF@0HdtXKKl zrRW{N>$JK8>jW#Jq;nFd+N6f~R#}ngJvIJ|d_I_~C;YlOLj($geOKo##1JOY71NDJ z(5?@(u;T%e<*svm%KQ#L4)nF~+(fpCXXH%bi4}CD(LYkl>*@xJ@hMvLn9%eDPH{BDaAK{l5 z)(~GuFRguR*!^VA=Mk~~_v~N`nXL`DfgUdF1Ql?K)(|(~O>V(yHvSBoI*haYAHzA6 zxg}R{o|n-DEMk<`!WceA5uailcQAo(Fo_>9g?lLBS7QB+nV`7?Y+E1h67@7&xD!7U WH{7(1pv_8qkAiuWNY4cuH1ZD)CJdSY literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/modifier/hash/HashSyslogMessageModifier.class b/target/classes/org/productivity/java/syslog4j/impl/message/modifier/hash/HashSyslogMessageModifier.class new file mode 100644 index 0000000000000000000000000000000000000000..1558d3fc5bcf7d3ea3aa511a6146883a4ba54328 GIT binary patch literal 4184 zcmcInT~iy^8Ga5(S|OI2*zt#KOh}v9SU8rkfu!I%24iY$Ac0K}S7y2JMoj&i`MIc8Ep3ZQyde3{_^SsY_ zzjpQa|Ni-}00!|J14}8qiq}$5cwMB=iS&7qEP3SRQApuwEO&6jHc(8WltL%Uvg0Ii zH-#^tVxTI@S|?nrq;LO2~Rx`X-&?5QKT=4!I#DUjTF9uHx0a{ z(CyovV^wb1p6|G|`RPdobxon`vRm^5s}|g{Ds?+<|KndPSO1y$w?d-e){0I^VQI$o zO4$|9U9J}bXVnSTvUjajE9Tt~|G>N45P?-7?&c;npF@j(*v%NBpkE#1i3?aOn+BTNO2w6JA%{)M4XuZ1oB z@Zh;n9|{+oniE`PCHC*dWuhdWy2X3ce2d}ip9xFDF4R3KlsPw7FOXGrHaJa?kr3r1FbL(Ego^qti zdv}~eXXL^Pxjh(h2EJo=zL0{hPtJNzN;qWyRU&lKN$F;S!*^`f08hF>l zH}Fk`6U{xhQ!5Mfw+y^z;xgVh@NE;{!FNr(h)X8M@jV0IH}M1fP~p&{wG|eFi67w| z6FjVjoYrrl@w^{+Rv`#O7tM{$myp8Z{{oq9D_79)?zBjC`|No;E0fU96}R%hH-$}wE{m$A~J`GG2L>` z%M0se&n`L-=*e1Hv1`i;r?D!0rD48_wr0xu|T%~1#wg!r|1bT*tPc#7yMnLBp zKs}ld5Zgdph%mr>CbTv~m**Rnk8n@4ba{p@&o;Rnid+uw1Z1=X8Y0k06VONm^!!dh z$(BH)1iH`!^nwOb@@8UeB`tqpTH5)0Ei>>C9U1jUq%s5Y_ybaZlVo)+?l&Kz>myOD z;}e^@eWDwnVguc`e~YeJu{`|{`#<_U12{y#FX9RMkdU5ZHi1is;~4Wifqj_7AzWdm zuku3Ew4SB?D?ITMtzM?)hGyMIW|z>x(z!q+a>Qpef03lb6fRO5<8LRQeDhF}JFP}{ z>QOThYm%I4B02B@ZQIa=?gq=FOg%79?E>|$a_0{BmRR1eH`qL}jZII)MjBw8x8lbY zUxkwqhpb)$abd7k=3#Z^8%d!-1fv*`sp#;3c!3njEDZb!2Ncq*&?iUZnROf-O{5d) z_&N@a8fl|Dxq-u@$q#X4G0iqek9MRx!V4c=$FbY#j&w5o4V69NVjah~_?+N{fFdtk z#sN6!;s4BMQDq^!?|jnoiLIu2YhNTEGm`8YA*` z%rUWX;$P8$O3=#%ruiip^mU$zpGA@$`{^l1K8haz^HC%gh!rE6d3poAbD4qX*74Nu zxDE>|92)nDy`~vvLfZyIQ*#i8CT`J78!Zjore~Q&{LF~FyvrR)ey;>-fWe;Av5uu< z^mk}9o{rOf-PN3n^d}JJBE7b*wseG z<44>(R^=V{*fnhU+BLLfbPbk}TR4YD}Z{XdeVa^(t|CeW{ETzx&c=Axre!nnp{a6+b@))|et@2}uA_aQa8Z6z&J$Dy>59?#u@$EuH=Ot~QxbLIA^Pe!rQm1Gw%G2JPgArfg4i8P6%WfPfS$)r9P literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/modifier/mac/MacSyslogMessageModifier.class b/target/classes/org/productivity/java/syslog4j/impl/message/modifier/mac/MacSyslogMessageModifier.class new file mode 100644 index 0000000000000000000000000000000000000000..e8886a71ceb0a16ae11fbfbb0dd0b4e9a6c580c1 GIT binary patch literal 4607 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 d{zb&@5sLqXKWvf>Rn8^fhqsTu_#c?Xe;EJ( literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifier.class b/target/classes/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifier.class new file mode 100644 index 0000000000000000000000000000000000000000..a0cb415f9820381c3d6bd8e707f1bab8bae37ce6 GIT binary patch literal 3147 zcmcguOH&+G6#g#sJZTaV9tHyjVl=}fq$R{rAwda<88RWnNkH;2X=Zwc#-WGw^dOX5 zUAWZB#?p=1uyK);W|A_NR+*iD!;PE#1><*bcZMWju@RyA_POVtd(L;BJ%9ZD^REB~ zuogi&j!B%2Lm(4JC(gx4P08iFJeZE)LL46=8%Gou<#I`~XXG*~w;#!6PHr!Uo&3B0{scMBT zK8k+-HA&!(Li08B12B zViql9shqb9w&fZX>t@w*JeoAJbuz2&obzSR1)@YiL&E~Qb5+;n9bZ0Y2{c@h5Oc0& zde*pAFsmg`AeZRdX-EX4jg|96usdTr)>L(A-f}OR^CfcjX39Cn(PT8a517%XehZlY z1Gw->+p)b7fyKm5TMM$&H^X|d`J@>dZ^5nzG%lNYf%e2?Uq%%~$#jZF)^lw~CNu1) zpplrb77CUtuy2#tX>}qqU$ML?YxSAThZ5;YX){!^R;-eM?mTzgo=9(LHR_k0tex2P z4SMe;(=-|@TAuHnfW7lIRWI|fs+Bc?3)?2o@0aw%a5}x&gDnFP_S;fm+a9Uw7Kj$i zoLypP3q*oOX5LmfFbZU~C$_MCSs7Y?@>cMvj<@lSj#b>`sNJw|etyx)ab~5q@q5d`n4S=@wz>G<3|}^LLU!9Ow#0<( zRy=>=DK;nYt__DWWryE{s8{wI{a>nss=_79DS8V^1!qPpHD}DHipTAu?Qw*}$(=Uy zV+$td10js@p6&2U#gKI+(qo%TygoA8*s&Y1>SL$*IXj#icI8sVqK!PqlCr_dm7PEB zS_ONR_RQsF%i$n9x>cEPGEuiLb!0ie>{aygW82B+Wi;~Hk1o>P{NOj>6=<^jNNchJ z`HoWZ5MHCi>)Z|VhTyyTA;jDRG~7qy+2kEE8gQ6voNw?#6O|@N=@f1vuMbJ?gskyE z(U&yPNS=|r4=pL~A(U*1{?c?0;p7o+8c%h#L~o-t`4hrjM{0;nf8HS0pFFAuc#$VAcH-=t;nr!(HGDy1ks(G8`6H4;o09a-KjlV zN7GP<@6OO~cj;$0(;>Y~2Il;jbs!{tV?2&iVvrF!K`QkOyumuWLA=F?$y^U|Qgl(L zCMQM!?=iticy=51jBY?NMinB%$J|29Dueq2AEwvQtOTwaaq|V#Vo39)TEC%CPYrED z+B#xA%)yY>sof!f7)CHkqobHmZ{Mloj5G*LV{yiC5-pVK#k+L#G&$o)Q#yk)m?3q8 zQ~~Fe!%3AVyY8?ZIIMB%4k?E-4AL+)YIOP(wfZe!@GZj(EaR4v_0_4dx|lVksfP9%I%c`)uHmJCR5iEH-#k}jekNzxTyxCkWp?Tn zR`E4ueZ;p=cPzzVomPla7z?@}rJR)wm|}>ei%o1!S%x7>zR!^Pcx5@tu4&MIkgIBP X-_xA3)#0DkZ8a!uGC&_F`7{3j)QboL literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifierConfig.class b/target/classes/org/productivity/java/syslog4j/impl/message/modifier/sequential/SequentialSyslogMessageModifierConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..0abde74d9b8b6eb7bd9a75b57d9c62e32b14b4ef GIT binary patch literal 2038 zcmcgs-EJF26#gbz|7PPDw+TN5k~V>EmbTlLlBOht2Ai}=oPuN;LGL#4cr%r=8+O+f zeE{B|m#9ww5=bOPAn^c5JOnR-_-5C!jd2m;qI)qj=gc|Z`OeSmZ-4&$D}ZbGB!`19uRUrlx{3*vgLN#v4FA`>p|!_M`6(H?8oYniXS@<-AAqyJ&xLe zcjKX>4v*T-p^PHelg?q#R4pY#Cz4-wq#u*D)94)=iO)`IyVEsg5-sJe2pH9%DFvqL z%9knk&)mH>HI;g>&+J{+fO1z^It`Wj3wSS#Xm(ZkDqa&9w-$HFJ3dg6z!^`*^y}W`~O}vJ40%LRY zCN^+K04DC@P7a$Uwy>Q;-NX*=34H#)D6a2Cap>;H|1z%v1zpQfw$xVw(^frs6m8e{ zoJJh-J+0{4YMVxBB0b_zT1r&oH)ae@|%) zvs%X;w9eCSjwh3rdFsyN0wtl_(?#(yo}gIvGmP7XV;J^XWR8)u%U6$)w~b>I>`L(j z6L!Ts!Q>D0Ph(slBFMxb{{q>UF-`t6j5y0UbGVqSX>7p4Tiw`i^Crz;iAXvF)BX{; zpHMo%)Ysqj@UzL?LXW>jI>oSh7)}=>Lkwfs*&1-p^qd!AcL{8h{5S(n&1wcuzG1$z ztUy1h;-?~>67jn|HXJ`B&*yotLr0KT^h~Gc=9x5l^bTYL{>M+ z>eh2u=^4_jF5?PUJuyxqbMlyN;oG4?ua0Ep;A+=-jcMz|v-UZTM4wDLYPUJg>jOlx uz4B!ByH5gN!}SqF^20=GBZ<6=8>5Kihl$)Jk;IrN00Ks*sHU literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/modifier/text/PrefixSyslogMessageModifier.class b/target/classes/org/productivity/java/syslog4j/impl/message/modifier/text/PrefixSyslogMessageModifier.class new file mode 100644 index 0000000000000000000000000000000000000000..de0a2dc91a83019c317492aadd70577c33b32535 GIT binary patch literal 1788 zcmcIkTW=Fb7(L^x*B3S#P7C+`6e`CXa*d3pTbUxN3sfZYk@mUh;Bo0wNhO+Vt4p=oQPiPCc4CM? z`F~>zWVgJ!^64o{UK2?Ba!2|CnVy}j;0}9Zi^oIF`bi+a9(2RHTvfV`#s4t;qOO{Q zllaoX2~3c%=wMPWkimBjmNDbtHtqL{XZWQtr+b*scr(Sli9?u`Il>QsCy{2* zseQnwNpZ%2PbL68a6*|R*hi!}+oOpYGeU&vVKnpakgd!gNMxF+gSQ8X6p1=RE6$Pi z8^c>n5c|B-JzlaH`?Og_-bu`JIcxLMmDfnUpA@5Kq7)5)q_mKG=_LTMVFJzy+MNXgZA_WaL&+=1SkKqQYufJfC9%iM&P5 dI@Of*haOE^B_`e2mtv~VkTMwB+Y2WC;zt;qcn1Ig literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/modifier/text/StringCaseSyslogMessageModifier.class b/target/classes/org/productivity/java/syslog4j/impl/message/modifier/text/StringCaseSyslogMessageModifier.class new file mode 100644 index 0000000000000000000000000000000000000000..9a8ae953052fafb08a2aad7d1687d2618c5bbc08 GIT binary patch literal 1596 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 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/processor/AbstractSyslogMessageProcessor.class b/target/classes/org/productivity/java/syslog4j/impl/message/processor/AbstractSyslogMessageProcessor.class new file mode 100644 index 0000000000000000000000000000000000000000..ef40679a736ebbb13708238861af80aed948d91f GIT binary patch literal 3084 zcmcImTUQfT6#fP#nIw*gXsjWC*lNWD30B0G*o&Y@EFcP^Vzmy*5C(H|GFWYEYp-kZ z6I|^>U%L9z2iv9Ss$D$#(8vCQ{*tbK`%Da3#Y3kCaPQ z&nkJdR$;grVdW7wM$Z@H{jKfSlt60$x ze{Nt2D;e0MWw&TCyAD6J$5d0(QW2Ys)^5qQ(w%bc1?MK~-w@4jo&(Pfv>~Ikgl_Xo z=a+V@R;ENxCbLm}Zf^fZAw5({@xSxc=Gg4@3m;l!y1eXW?NLYi^tBf^Ri8AbiPy2u z#2)N5P&QG)brT10*nn%I3hA4pCYEtSmXCPibhN96ekONp(}{_R?p&^WY;34l9I95k z4cs(w3m;3MPuMQXc-eCbDWTlNr?_om0H2xo9Cu87fiET0R~mLG&4vl}yU0Wugfxs1 z6DKid;%i*jF!O&*9kW@-aC&~p&XSKKFNyT*0nUtS==)EWPhT&N*1?w;C>H&A=SZj; z7c*~rs!{xY*xvKZerm{z_MTnj>u9;Ibt_x0aOM(?4elqNZfw@4B7dI!`OwhYXjOYu zH%70$1v0Lg7u@;?RfZ}ZwzF|!^5l4CdaV9>H{5b)_dO%LKTC~z>IGV;Jp+4cCQ3ot zF})EHJ@e;49?$He$h|=sr;}?BPbYb&@w+wg5L!ZefTqMFH1qR|GTYC!ji#V$ z9WjI%pp^j*P{B> zK_eD;f=y9=*5nZM4?#IZjo(82CwuMUQLJ4F`N zl}J2?#aU}C=<5bWHx^n?^c1NBS>HK!n6F7o7 zyoq@}MnxQjhj;kKy^C-8E(zfaexh}E_s|cM>wuR-i-YGkj z>L}MSRxQJ%PchW{4V8}9!N>77)05VVGsQ!y(s8`UT{G=>5R8D=qV`H?4ql75WH z#kNhq!hDF$6TOeoa`7RytfF-?xr(jERl+<_N7>fe{{uD=aBKG}wyi_$V(!2sHe-ry zeU?))!@8U&dl$&UTm$5E9dfz`c{6Kw9481l#K4rw@Vr` z*(<1i;wEt)O$woa+P;Cn%k*)D$Sl&3`~ulKIc&msqYiTzt3k|IaH!aT3D xlRbrK%#Tn<)Tat5CGAs%l;Q1D*o1>VHo`bj$!>zX0DbROImm-BNqG}a{{xSCv%&xX literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/processor/SyslogMessageProcessor.class b/target/classes/org/productivity/java/syslog4j/impl/message/processor/SyslogMessageProcessor.class new file mode 100644 index 0000000000000000000000000000000000000000..219a129408a185b084d46722b88d848da7818c61 GIT binary patch literal 998 zcmb_aT~8B16g{*3VmAvdAPBUg^{F(`jfp%#Ot45&QyWZ66CbDBu@2epkeyi){*}T5 zi6*{jqW{NN`Q)m|8>Ii=WclO2={<((M7-y5V7lpO zUoe#SWhl)HhC*v+#8B+031zE28H#>98;fYj#{p$lddepeoTN~kCyVBT)C`Um<}d?h zc-xvU>4a4+mv|$EW=?O-JZ|mGcPPEWz8~Z_;|x?B`Qk_>_fWt4Zl5Oa;-ZS0izO^F z%$1J|H^ChK-!>eKwTZZI?q-fAt!tUqxPUEGumA>|A`1@1G?x5S64@gCBZYJ>Q{<6l zWJ~R9uutSzSfR6=CRedazMB=`UJ7Gl4eOLin)k>i&35}cD(x#+{{WVV2~ekL4Pvu> z3&_U(9B2cZIZz{oA#RtjK2jfTDxDdLCiQRK@O?rAlW+M83h%B_yh7;`rF?YO=AQro@@dvg!{x<*s literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/processor/structured/StructuredSyslogMessageProcessor.class b/target/classes/org/productivity/java/syslog4j/impl/message/processor/structured/StructuredSyslogMessageProcessor.class new file mode 100644 index 0000000000000000000000000000000000000000..00a3f3785ff10d7fa458183b8422dc2104602140 GIT binary patch literal 3245 zcmcguU3U{z6y3KplQa&r#8MhQmKFI310|w>KnqgZLW5~qNhnYdoK7ZT%48-^CdK|M z1qmo?`RIfH!x!It^}*%7Geep-si14&%35>3&OK+JbM`qmzy9^p&j3zieE=i)B8fEe z3CznyA%O)sE++9MZpv9Pj#3f>$S1kDC3lwO^0xfkk$ZQOSjN31?&B-De2~OLd@WD) z1XkiOow`ZV2q0cAbW=JN}YxH_h1Z`8&V;_~)MM z0`aBUo5kEhK_Hc1)z|c_tvl6h(f2H;Iw6qA6^f;)!t|_wk$1gnw(hy*rr}#_mcO12 zE;QB~wp%^3nzd?mJ6kgw4ZUhgIfGNz%Qk$E7n+_~mTIGEF}O4z3NOBvrNP0nS<#!e zp9|m`^k`78*KNztefm?-Yup)#l;_FXEypZ0Yb&N#(pPNmr1Gx8|14LSZ1eN z$BDO2umqAKkg2T{8YYY$bWhP>m#j(!QS2q-RLXQLQ-)^}Vo2yYQ!h&fYMETFTmSNM zPos&7Zdf+!iKUtoh}q_vX_Mu)rt{cwpExQGV~l{tRUE-s z92FH+oKU#yJF{;t?zrA7D(yDjv&^t>O&M#!*w@z>TA>;v0A>8t~(2s#wDl z72o0lEz!9C&fAfS4{=DK^xq6kt+4ayhTpr@2^^JbyUHL}T-eNb=Bpf)fWR*HLNZ~| zvs^DA%)##Ji}IYyN%AY<1%Z>@f)m|rY;$CPX8IpahdNTa-tf&D`>@gUJk#+dKj$sm zmaTz(f=^FxKQ}uWwC#AEkB(n*1rBtBjgZ}tPRSSHbv=Z%AK&&uR~bx54TXP`(l!FoQ)l^P0j zSDG5&Nj6e+AUFZ~pF(`cGXbeX33fl_m;HcWY4RpvOOvD83-oEJ9naCPrDD&aXfF|e zj>HCn5yU9>84(;qlAwope=p8=AQ{Cc0TQWST9Nuq>hI%ta2x&F30mARvX3BT95x%7 zWPC3LhDJhVks+#;y^N-W>_w4D83gH4O#1-|>3v^^_g6ab#@cw#(XSBiVK6;m(~FhBsW*NLkVYbs-#pk#}CkP!=oJmSoag`3rvaDhn zGjvVPW;u(|&I4S-b+S2uxpuLg3+@3UsXfo2zQPD&u=g28pJFsB_OMXHVn0MZhcU=U LS|CT=eYo*A548mp literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessage.class b/target/classes/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessage.class new file mode 100644 index 0000000000000000000000000000000000000000..95f1fd5ce04a1d0ec01efb42cfe1a1b7108491b2 GIT binary patch literal 6662 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 K|3S9Z`Thd?IYxZ| literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessageIF.class b/target/classes/org/productivity/java/syslog4j/impl/message/structured/StructuredSyslogMessageIF.class new file mode 100644 index 0000000000000000000000000000000000000000..faaf1b7e35e9b9b904254998eb9a1ad3b4fba818 GIT binary patch literal 240 zcmX^0Z`VEs1_nb0PId-1b_RBK1`b9BuHgLAqU2P!%$!t42D#vpqSEA&(xTLq;L75h z{B+;c;^M^gR8Kd(ti-ZJMuvd=qICU&qWlz~s?4&?l1hD$xPCEMu}PMGW^O@_elA3l zelgrIeVpbpG6;Z8$Vtpg*Y{7#N=+_dWY8mE3!2;57#SEDn1GlW=sN}=%>pEu7+3+7 C6HCkh literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/multiple/MultipleSyslog.class b/target/classes/org/productivity/java/syslog4j/impl/multiple/MultipleSyslog.class new file mode 100644 index 0000000000000000000000000000000000000000..258f79a2b7efbe116aa382a05523920d534df743 GIT binary patch literal 5110 zcmbuC-ES0C7{;H|-R*3*ODW|;p%hmTC~bB5XtnLO6)Yf&EufStelp#iZU<&}>db6w zH6|D}MvO6Bcwyp&F(#Pkg(L`~iE^!1{tf;g>T_nMv)k@0+ol&ivvcO0=ltIHyyrb{ z|NQsY-vJ!KdkO5ot1Z}$*JSg$f;SYrso|fp%N7bk&&FEL%5Am$D}X#94t&<7UZr)RHr;8f7gO zKk(`8TbY0E2(;NtwqX`7Sf*p@0)YJW7F$gjs^sh^hQfT zbC&n$NcW+2i^cNVOqu(;J;V{xGNq{5wpyTd$GX=hKIu*HJ#%=yljx+6+Iqr9I7FzzVF< zRWyUgO6Ome7>2f>5v!l-4UU5sBrAOpn>EVz91XPR%1+)~B&{-|=B`ah;@&XgDjTNe zEOSww1~=d~TbgQ{rJ$1=7&=yYFw>8Oc0ZDW zeu1HNc`=yi?#WgLel25Wtw&(>R9CZ$cGDlsaAix&uO1@M#Wf%Hy_Mfd=^ycJWC=;I ziHm00%4w%{ndr8zOq5T_@ku<6y-9RoPZEzIC2*oatTj%(0=p|DwW purMeIKNab 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 SVDYaA7SBl*&x;4-3;zYvJc5}3 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/net/AbstractNetSyslog.class b/target/classes/org/productivity/java/syslog4j/impl/net/AbstractNetSyslog.class new file mode 100644 index 0000000000000000000000000000000000000000..b582da11d84d217335026d1ec8b61d5e2df5c97b GIT binary patch literal 1867 zcmbtVT~ixX7=BI?SV*=Bq%D>YE46;W7TAIy1!6UZ(xyfnjb#S!mdz5DNp^Afq$B&IYa#&+6^&h*ls;16+p&ThiT&<<6TnfL5__C3%0^}J`F|NZ+P0H*Ot8vU5+ zMITHht}8LEVMfDy8fJSimxhM-Gw8y+dUYd%1uUkqgo1_-(#T>;!%Ynz3iO3e;989} zCkS2NyH{Qo5O)R6m3%LhmM7P&M$75?^RFM0d$HM0tg{-38ZklJX%zrV?S4x)N!zBpe5_oh zh82b-E0njsv7H^sW~eiV3f*VxjyzU(flFiKFDqka>!?8jJq5ebPCs4sTY>GYxGLF! zQx%(1rPc8|F6$V?kd9%D==calf#UyegTTlUJx=E6HQJn1%_!_o*W*b!Go zo2^ieDmpk#$K#VHonX_lozYWy#^frms8m1JQNps0*KkS0EgdVkt>KQ2GB^l*M-g{O zzHmmAFXyAc%&VO3L>s3opvP423`F6TXm}E&lP@`SaqJlDsxolB`jQ%nyi59Vwog!u z)AE(T;=hl&<4{0r(^lX@hp*B7&~_~_eFl0>I%fDUU=GW;fzSEL>ZHUF+leH& pZ?HeS*l_KzD_4o8ewhPg*Y}b885z|P5p|@SE7)8?hpJ1H{{Zc`=PdvL literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/net/AbstractNetSyslogConfig.class b/target/classes/org/productivity/java/syslog4j/impl/net/AbstractNetSyslogConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..0e0b90aaf2eb4b6c73375a0a6ec152061c0142cf GIT binary patch literal 2286 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 ItSYzu2lW;foB#j- literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogConfigIF.class b/target/classes/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogConfigIF.class new file mode 100644 index 0000000000000000000000000000000000000000..bcd9463293e6382b8459281384e6f5efad382451 GIT binary patch literal 732 zcma)4+fKqj5S^8q0scJ7Y_OiGBmwJMauPw zdT4uMBqQ4ngW}5I7Zo=;p<{;2E5upD<#RekmL^wVj>|g?BsNAPA0_$aiT}}|M5vm< zcud>i&*V`EzxKUVqik(*cw8R2BWQhd%Vkib`9H~Y&kKAT+uSAR>V2zwL*@(VdJb8Q zxzlN%POQ1b;KK7AbLM-afHpekYGHLzSOH4T}lW;Nc{I0yNtUx1yc d7B#=C`I5$a8kaS$XuPlW)lg44YV_WKgAY1Y!j=F4 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogWriter.class b/target/classes/org/productivity/java/syslog4j/impl/net/tcp/TCPNetSyslogWriter.class new file mode 100644 index 0000000000000000000000000000000000000000..1f2e61b62837c37eed2a14bcab23c240de00b26f GIT binary patch literal 5457 zcmbVQ3wRXO75*ogWs}W>KnR2-0-=H?8z7B;R-E&V8JF&VT-M z&YgYXzfbH3Fbn?)VLmn$VjeD&=Ht?QLYm8E;))=y3?YckL0lEW)wm|anNLdZ+9DL< zI%&3q@F{#+dY_Tr_0s#S^lp&mMtS{Q2%pDR*?W^nyIJJl62h(6T!h=OO_tm)vtJ0} zjv%&&Fd28s=DP}TcL zvziwxP?jnvZnP4%qbHm$J)SZG>8=azJ%96-w-jhjw7<=8IyTyIt4BdyiyOta45ya+YC9X-2lmcWFv7N?YYj)i=oWXAEbDNG zI9Zx|5Vh$xd0fMBALmJEZldJzaou*ja~hL|?$GW|v(IR?snL8hVLJ5+@~f)56sV0> z%urC$VkV5XRNopS*{QFIbELGziV`%P(DB_LRGnUvG8P`Uj;oTUVGaM2puN$OGGGxJ3Kk@}D^1+$Mwl7cbT8b>!19%M~C!%A*cP*GLwx^08&-XW7T zL5m8shBvIBrfSf|&Ghr4SS)GS_PplRo{$_F++5Ua+1Vuu#vOYr-P3O+$sVOyLE&1% z=qF(72$-^({Iy*k4JaFaA5{wz#`>(Dp))r`jeem7Jz3a8qWcsb<6Apa(c)+-nKTkk zmOtg)w5pd}OBf6XE76>wL)YnX63Vow+E~vN)2eM=K5&v49F1G{09a)?V0q`e?(}Wy zv>Iixg1~y=3!hczG>E(NEb8oo#S@mNoc@&4;m{9#JYsarh?{*vunyzml#z&XXWlst z3W9xfgxQ-#y@qzI zP;kcarWp+faF9WHy!*3xBZ#Lpd=+PD=#-`l&uDlS&uKV>!$CZ+;cIw7!;3QV5?eG@CG`9cr%E%G<*k#HGEgrc3~A`&drEJiK5{2 zVa)K-^2$^~yfQ#A0rz_vz7Hn$QJ!-vO}o!|gUq;OI+64f4L`-tH2hq2{RQ3);+GoMBCg?A__c=Lh|Ryn?}GTfhCj%flz8@! z_>=U`)9_~*`-|Z4SNtuAziaphmIm=p4gbQw71R%7;(Hbpk4+ztDnqkncB=$@w$#jG zzz?H}hjx}BjInZY+A;DWgMgA38{K*;&NzwW#P^V7c&uC)GVKnF1*peJx@C#Ut<=p+ z-dKkbwGuH#C@U88V9Ea#Ql=JLl2}$iplWrqqk=m^Eod`Wf^=@Y0|(|aYrQLbijJ<(H3+?ZFGl5(@B8IMc#q#0!CNJ?6g zTLZ@Drr%u5YT`qHmI$ptyVKxo*F|#E#Yj?}eIMZ&ITN7N4c5_d{N*ay26oIk1 zhcVg9-fD8BgnGKPUTJX9AhO3?Nh-+7+*%<9_(VLqijneX^*#Pu6ulLtM+M&vqH# zRw17~ARO5PC8F#`o;3N=sFA|m2<+ly9$MH=zzDY06g-8WI45ExreO?D#(31Al{10ZX8NPfaDkKbe(cn^qefn{HOC(amZa9Mp`%uAp>*98T05wr4 zMUmuF8pSP7V)EH!LgfLGvXeS4!v6dwO46+pwRH1bqEJU1 z7SQe{+PsW*cF?+u5u=P=O6kTX^zes-wJwUYY43?B<7_>pS70g(VyAG=G#}4R^hq~& z2yM3bXlJpTOssfqbTtHTZ22yB?KOwV*P0Bbh`sp_V38X$X?(b~^h47#I5C5%+n|Y+ z)5S`ERfWH5Oq)MY;10|-^us6?GfPk2gQ^2Gy}HhikBA!q(`)u;P{T;d zV7j+`27kN=gad~#Dje9q9igxq4tSGc(rad3y|;|4*+!;OVtM+=<~sGNe8qjqRpM^% z?64{rr;nVsiw2Cx6}W1ENZkYm*i4hICS=!e_F7D&lc(@^ni^csU#V_j^1PA3x0NaJ zW>V}H2GOmA=yoJ<2SL7*Al^lp4^!&BlyD!e!~NWu=In!PALjofF1$YIm$kRglL1Cc!gbFy~|A*8wbkkT;FSjM=KrT6!12^@lFo< Ng}yk2ib(mo^naCKjMM-C literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslog.class b/target/classes/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslog.class new file mode 100644 index 0000000000000000000000000000000000000000..04f4045cd3ed6e7ef328af9b5a756324fe8a8989 GIT binary patch literal 2111 zcmbVN(Q?y96g`{Rks~V&q=^HR7D`L&*ffGRkU$b3abgO%3{yfF`lcw0BSw)tk_=71 zpnsCrGE<4u?tCgKlx5VYatG%mx&pCVdto-NSuigN-gj*(#;o>kxaY@a- zH97mv#0)MQxME@m7gaE8V9vl*6DF>ycwP+)YFIRI-M|fjW3h}p$6uFG?1jO@+baU% zj=)GQ4C2HIl6A*#%ly3D`Du6PuU`d% z3kl8DpIzBX*cmcRx{-7e*|PzGdU>iZ_9Gi{TsQ7ecLau;GI@Ep@<969A2&JC{7NE}Zwnq#Km)2!@6RK!aRyh!suQEPk$sLDy4=FHNW z_!OTp63T=r4{$d_nIOtwrLu<{fhxcAw}<=z;25Dm+8p65f{YX50C*w;KFgdO;Z2UT zIA==eGAWcC^EHMZ@55+Re`7R&1EJ?oz?UgrNoQtw1x8NhB2I%PUb6ovm4zGh94`DIL{)#KeZRam3< z;4^!W$R)*D-GjA@kslQ41x5NItt+G`dS4~vnLR^>Ij&w|&t@@!t6gR*<5PVpWqfL; z)d*bZ9?%-GRhFf9JF<&hL-QFuyIiD2mbiL@oXg#Q7Fpfdo7Hntf<5V&;U8Qdy^pI- Tt~=!Vo?LhP=9;FK0oZQ=tvK^M literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslogConfig.class b/target/classes/org/productivity/java/syslog4j/impl/net/tcp/pool/PooledTCPNetSyslogConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..5a1475c536d293cb634a19b8b01a91b2ce61e195 GIT binary patch literal 4906 zcmb`J+fN*I6vxl7%PuSfw545&K!IMDp)$qNE0kJpbz5j@pB4;pcINXv=lp)Z`TO4& ze-cq2eGsD-%GA<+(%8&bqZj`||8OhIW`T{)<{_I$Y;tV!Yz#Ign??5Yn2p88X5+9a z#4x(VW;sevqO=mFccb*4M7wOw(o?xv&9ZgVxRo50NV+0X{fKGUPRej*Q@Mgx-SMog zXX4O{UnHu{r=DC&JNlA_iAjl~XeTo{wD{LtN_QlBC9fM}OM2Q#J;-T1IHTvaNj;a- zZJwqZVnN&}UqZ8f-cAHfNKA}*4KX5$3~N!R-ni%r zC$2C?J5SrHdf4X{<1WB@k-9HfZ?wQOk{(#JE$~`ttPAU=x2fqatlw@v+8_uiwn!Wv0*AwiVGeJDZgT)in+VIWjT-sI8~VeEI~(S&@37L$VvlfH zw(D>#x!%gU8aRkzC*)E#imEBmT~?qY+=<;0n>GtpS{ug(Mk!RsgAD4S#4Ot9%DMW!A)F4L=QdfBLSn#};4K{glI49WC9-InPh4N5e! z1AAYha_pT7)P;Mfg>X?&J^r^+8-BOr z#;c+O6y|*3cbHS+K9LpoiNv^1p>J?;}3a-T?&`$V4HCsO4;kuCR$gyGqVcOmVt zeQ5naA^aj5QPxOOqN`NJCZz18@G3==+Et2jM~xC%rCM&r*wiT)mAS8;O#_?8-{Gc; zUV}YP4X_6xVIS2}9Ia;j+7GEM)B$@KlDh%h3(+Sb`7C-b0Bjf|C$Ul%NYqcK&|=)v z9`0Z88Aji@(t5mojdtxU@iB^mQwH&F5bwudJBSa0_!x+fgSZbpr$Iab;@3euhMmF0 zilFj{!AED191iR_)SW|I_}6*#ak#NxJUwe@hcGqy(4ay?KQx?!h9QiMKox6<3#OumQBMPtU)U7>p0+h=+FA6I zFA@I!3gPD(lDJOX8mhu?9I~6j-?K)0cUHrhmk9sa3gH(T!h9)sqF5>;d%Gb%jtyAKb8|7z&FJT?C($JwDB_e;-8NCR@&{Et zg)4DRMbM3-&vhftoNCVvZmlBaWskB>X?;#{A6bLDQ!axqi7LHPMpRcMszX%@qR~L2 zke_HWkZ5cRqEIPTg6IZ_ra?4Qfr#%Gj?p+>hUJ?;g-i|y$0+ifFGh2LL~lT}SUiL< z@HrMyI&f{2U}A25?*ist8AzlUnh1Y#z=wp;1%X8UAol}7t_Fid{UB+8WGaC0?aCk% zfjO%2=O`NpGPy;LYDzRBM~^_0M~;j#qVlTYd!C7|1rpWzi5>?MT`v+1d37A&60R-5 zh#VCFvs4CBo+JLyV34W69L4-OS_uTX5uBr#ALK)Td{hC1zjPSnW*|tNALQdekm+EM zIzPxK0Qs~62!CoZ$PC?r?Q^#ex5f66{i*pZ5M-9-yu}+*Bl|%<2gnx{K=@maU;HNB z_I#C}b@hIbF9SjD(A^-AdOyfl0QtHC2!Cuc$h|<220zHRfgo=MgEaU-z5~ej6+rlF zmqFeR1Znhx{1^ywKNzI!8&~X_p8)c61rYw+W{`I%1$dS}-$c#N&@R7)el6n& L7jK~l?yU5GSu7u9 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslog.class b/target/classes/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslog.class new file mode 100644 index 0000000000000000000000000000000000000000..e1f3ff548e10ccaff2e2e844170b63c79c5c5c17 GIT binary patch literal 1704 zcmbtU$x;(h6g>|znKXidAaO<%nUWS~K~apNXhg~&R#|SE@QjV2J9fXQac7lFUAoY} zu*z~;Sgu_78GeZ6=_E~B#Ih_F{f2wb9nO9C_V=HkzW^A=TpUS^ddt`rY(plBYyu(Z zF&vIleZ*Ui#&9f-<2d1IPR4M`+fTC}ECo9ArX}a9t4q>ZFqX=c zB=dHWZVfu;y(tW-`=%=}owuEmUUBT@YEhYwOjXlYj7Ns<*4(mPI<}<Cg~DNu{e| zMR(n@UMS=ja`SUi73z>lfw-3j6E~kSSc;g1Vr5OwZA@8C3en+(mqT#xy-}g7Y??>R=CfN#{`X3L$rV}{+57S0- z-mF^6T$O7t%UNI>|IwQl{;M~GiTE$Zrc0Ehy0+GrJwwBJuY~%#&Rj3!*s^O^In455 z)hKf!Q$qp68%ry)s3wQ+u&D#4HCIX6BwVTH9lIhORbw@ShRsOC*M$#c4kVtM#hnk2^BEso#0}*Z^y3%0}(IPR0 zP9~S)4}CjHq*;fZ7$Bt)QW$52rm-Jaa1ir2ge44N1*33~!EOwqpo7y82%KsB4zqsB2ZvF&p(ei1+XR3*B`;+0K@rq~|nU z@871*q~j64Yc@=;Bq*An-w>pf?JdMVylOU#wdVGw;jHVMmQ=KBVAVm4d9bK>?@U+F z%BtO0Jq$axgCQHXO{SBVo3r@=Q8OVwc;BJA;XQ4i z_GEs(e?OeuZl`qDmd^2}yL>vUWAI(?s>~R?y62gF|2z9K`}{iV-#Fn4aOtbu>xUZaOt%+2lIsLQAv2^-NKY)D&eXo1!T;$Jk7>$F^fx(f%l`xzcv&jTG>hkEoN!qwhQpqqBltdw z*C|42Qn*a`R=84fM6u+EdSRS^FRBSUgV}5B5g4ZnEfNLsgCcCAY!o)JZ}=IZ=Mj(MdXm8H>yYBA>BG!P-ngy>Prm@nLjMPy*3Y&^ZE~ zEOb;vW}Si`E6_nyI!$M!_6(hcXM~mL9M+LE@d|#@?nHG%>BUlJYwKyPEK4oqiRh}|85N>>5s>K#1hf!V#NmUz=s;?~21I0j3 z!^kYL!gq>%#fRUlak+R!hVdIS7Mz%%3vJj^P?vb2h|ce{dQw*F2EZ1(K;rE)kIOs8 z!WTn9qP-xuLqQh8L884NC4ejq0O3o{AX+Gh(hKr16y#Dkh|&wP43L!pApFWO$mLLw zSTD$vP>?I(AYHGJUz#<5JRbnU&m4nXrE9SK$Sue@o(MrQG6o&uIxz5e%boR~%*lrAhcisqti8yqS;eG95NU2Rp(n(*<3m?FT60;I$ zhkD^fa`;aE^PimL^XvTsz$L~3MgdL&oDvKLxA(kaR%uRfHkmHccoWks&IM&w%UoPL zk!g#f$xqGniD2BaTE@n_DZO^tR&A3Fopz;5V}0Y$soEUvoHupRj;_fMm@0L`=Q49s zoHMpq&6W?`vdUyi%vAm&#ohd3I~u{Q(t;LRt;@v9jkFc5M>e(gDy8zZ$Y{<+;1f%Ay9-mX5Sc04XnE!Uk9sxnetv&Zw{VqWl`+$o*1a<6tKJYy7JoJ3%Ioz`I JIdXdk$KPE(kgNaz literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogWriter.class b/target/classes/org/productivity/java/syslog4j/impl/net/tcp/ssl/SSLTCPNetSyslogWriter.class new file mode 100644 index 0000000000000000000000000000000000000000..c3adf4943799ac20cfaa165b9bd6ab3aa60c97ec GIT binary patch literal 665 zcmb_aO-lnY6r9v;S86}Bepe9$57mP~@TPdFA1I3mtM#0&u}0TT$!3cMf0UjS51z#z zCBChNTJ$1#$Q$0v%#ca){_*k(U;~SJIGE032D2{aT+B0!$I>VfHl&G_j?NBu8Q2j+ zv96=oipVxZn8@t?a;Y=(wzk5M+g6dXI}9VW)dqu8*B6qZ?5Ri|C$~*$PDL}MNyXCv z*$OhJzCU#Am5Lb-JZ)OMZS+MFSk+Os%dbU8@VFa?y0v-D)onZEk+j?fZ63!V_kHiQ zesV0W-=mxxWu@6-nAA-xROIX6M%sN5SZ%rt3$;}*HN5M23~iDo@9V?_a$lv#tp4h} zo~jGTW6VXhfCW?-_WtF}3_E}E`5BsFX%MY{HA4w0U`yIvc`1_6Vi_a!~`V>#?Rj0WNZ=h5!Hn literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/net/tcp/ssl/pool/PooledSSLTCPNetSyslogConfig.class b/target/classes/org/productivity/java/syslog4j/impl/net/tcp/ssl/pool/PooledSSLTCPNetSyslogConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..bbbabc4ead9de8c73b2e3f68ad026e22a48829a1 GIT binary patch literal 2648 zcmbu9-Ez}L6vxlnvYj|i2sk#xPTB+tI1WS&g|-Ap0Fy9=lu2<2(@Vt>j;LaJB$+mS zmfrTh%)oeti#|XfhDTufKPw?CvfMh;@yuE8>U{jp$L`;sKKw;QtMoWaQ}q2fP10=^ zYb@@txXT~zu~=uZ!QwuP2N`;pp<0F>WoR=)TY{z?-8M9HPq!VzYQLyI5+t4onyguE z$JN^Io@RFS)cp9`$KU_>?NHFz&-!u0wQOC`x$W258%;H}c1vxzw$X0gfxpk+cQnWO z#j+0sWnH`LxSx&so4!W+uF*E!bwSC>(w-otW*xx)nQf!3KkFXt>-Mg;Z_0>P6RaAD zvG)%Z_t0RzMmfEqcgKpC`-Wcw&D)F3S$Fy2EU#rGZ$5h+8tGdmO>Nuv_u`E;F zfzS^cjqTmq&NJO@NNptl%HV9ySL%aF)|qkamDV&&L_xjkKt8k_7fZ*ou@vLXWM&m< zT&xW7T8R0;b`ve#eHs*grm{3>4<#q8ln* z{`nO2{Ysh`13~!{#5F!db!P&#m$u>RwmiqYG_0=O)VB<7`NF?6XoVY`qY{;KRG?yx z&a=3{VwOdT7Fk?jag{}d#gd?n(~e4HJ_K$4PY+(gf_6^p=f8$lQ2jJ6L+%DIfS|{x z@x^y4QYh~t)wgI7uhJCZPE!gkn5MJ%e-4jWg7Tzr^YCBc{>c?BlqO~eP#j+ny#mX$H>N`sOi9g=3rsd%+>Bbw(R4|y= z0@!uGFX`$sCci)GS=p`I09y-zq=TBL}8$tcJJfIJ)m!k3&u z)L0ND3bGjs@^w6j5(TLP^CLi>4*}uVfHf7=FH-7QzaGfZ(A`t<{jCsr67rv~rZ#2nYfKo|fb@tR}nZ?nZ0>iC69P z#w(|FriHQ2=v_P0AJL!DyVgG6ZW4luGEQdlo!;Z~KJT0S_22I=033rGM=!>k(SwU> zHxcJ9qv28R>-f)~DuGM>mXW7^i^lATzLQRI}$x_*)q3E4r#a-o5lX&j#aaEF8Sfc6nJ`2(VDsK)qRW5;xoM_BLU}ReeQY~G> zpg&`i&7TI%C_g!ba}%Gtu5viXF1N^>Oj9MQ#f z#2DLS9J;*s5qeU;qUjl$1su7md-|#i`Cw8cFhrW&-FQ58>x1beTHMJC- zfuXeE3*H{)?|u@y&_{?;+#Tg#iZ2PxaSY?6A8>-9v@zX&9PvRJse-`pe0f$0Y1;DP z5bcQ36JQ6CG^N5sB(;Xt$>(TW?C*bZBuHSVz&hFoBH>ffu4w2740T2M(D4krXz%t< zIHvS_31?^MRP^zyzXxKQ1bz&1?2W1HAHVX`ynrmG&{a)yfXS&EYdFK|4Wb?And}&o zyod|P@N`{S6S36n&kgT$Iq(YRqx<7T&C(`>nj0qm>2n=Gr@XBh*L^z-LAQqdOINf1ph* zYuNo7w>xMTSZ03LiO~%f|5k&C&T5{GQJ=@xRc7{cRXr0Dzo>7&S7QFnN`sA1y-zM+ jsH%C=muK&6v`3&=@D;mhOf^=}U}`r^eko_8zT(*b?Tnga literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/net/udp/UDPNetSyslogConfig.class b/target/classes/org/productivity/java/syslog4j/impl/net/udp/UDPNetSyslogConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..3e9b0caf210df8c163deee2493b771348f1ec955 GIT binary patch literal 1274 zcmbVK-%ry}6#nkkt#g7PxPkitQ$f2iX^cLYprC=6j4Z@tu=j41a!F~Iwj<%c(x)aq z_y_ox`0R^s#&d3$#dMGuUcS?N?m6H0oqPJ@&$sUYUg2dC_prgR$?%-v1%tuR)X~zh zrK2sd7}|lf+`b)z()Ug}2Lj?yV1D2C!pQQXzU7YX-22~^UrRstngaQE(v#7yK-OsX z1+;zt)D~FiO3ywTUk>cx*c!N$S?c;jqP2*e&Xc4Toy$<*L)Q-+a}@Ze<6$JPWOQv_ zSXY)AUWcylyty#t<;XQXJ2JXDG(9G25&zN;h0^-vejr*R?_#c-d(F zL$S|EnxWY9$HCD4B>BBoX2;xS%X3)3B14&>#!zQiV^|k>d)KEF*u86OvIT*?|0Vc1 z2&2FnMyWmG2@3Q(0s<8jai8KGoidn*PTw>*;X}&2rYI=pS~0{|RkB1_q*CA!G?cJR zUvo(jWlD5nf-)f!98--(vCyiv>oGEEj#UzTtT^TcC=HQY@fKxvWyC zO%ytG&XR&o3Nf;2fg19tD}hE*HWkpP0&IZ=*m!+HyGv&tGT*Ak(9*08}i`K c>uAf+zfjD8_ncR`wqi+ktW9_PR8>9u3!C2NnE(I) literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/pool/AbstractSyslogPoolFactory.class b/target/classes/org/productivity/java/syslog4j/impl/pool/AbstractSyslogPoolFactory.class new file mode 100644 index 0000000000000000000000000000000000000000..38cb3cae2ef1134bc07fb5772e2d79be5ec8e67d GIT binary patch literal 2850 zcmbtW;Zhq_7(F)x5|#xjP_VU9s8}JPjUc6!K(#=r&;S)ENY&QOW(!M`EVH{Q;uAPN zfj)tM>x{xsXSBb4317r6XK6NMS`L1F5%fYF%fUfol|I{YR z_!&^t+1VMQMYkO%FVGjD7~6)qX{Ai3P$2n~+)6EGw=C0tz(;=FFm4xZ|F%F~|G+8_ zPdPbDpfzI`t%Xt{Yq={%HqVu|jAPOggU0YZT#WjgwkI%sD#AhRTJ4g<44rV?T~g5` z6Z&p{!+1CQPX$_wmzEOhOq1ukGlBDYqqvcp${U_HWqAJGuT5*)=bbWIi&1k83}4x$ zB&}dPvy@Q+9sL7UXlj)R;kB)~wr{xtV`m_&&ZcAdlIfMRm>14&IqLcTqd^0GPIgP) z$DzIoqlTT3i)Ol(;ak#Qfvco1^YX-8Xv;dT>+Gn!EXx`XPrqJPhr-CywfvG>ti_x- z%jJfU(t>(3ZyB_lv*YoywPmN|n%0ahGqt-mC#rJny0lEkJLuE#HoA3OMvsnOT#4ba zjwkqvm-zYxTrNFeFBrG z!T#?KATT6Bj?267KlHrHvftE7)Oq1v4v*b0fcD z>2Z9QZwvfZaPCO#LnOp6h{&N%4$+^u9>G^bqacpobOjbH&s+M9Rtk<7eY(DGG8^tyh9v8UZ7`-0kXR$%H#3QAH`cD-tq}}lVlXZ)IYlvzeE54 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/pool/generic/GenericSyslogPoolFactory.class b/target/classes/org/productivity/java/syslog4j/impl/pool/generic/GenericSyslogPoolFactory.class new file mode 100644 index 0000000000000000000000000000000000000000..07fc35755f7329013d5f29c57c7a7d45b0bd5ecf GIT binary patch literal 2592 zcmb7`=~vuT7{;FqQ>KKJ0=6hEv_o6#0F^0}s{{H9pKLB*$I|EPSW;HJ1mVuXW zJB^pqcqNVAM6;(5hfLA%;_?A)FBIvMR4mz6=w4n2S4rotK9a~GXL+1JUYvH4|fhuoxaEgR*s zRxEo-=WMT3^4uT}9VL0pyzqs zC%pQ9^C=kYv_EP>3O-Dm9SLHWp+Tv{*e*-tHEds7p^gQ(oNe2;qMf=WL`~96>}E`Q zW#86=4xeR9qS8+4MEy<*Wa2WOF=1go4co*5#G~tw2fPz$s|khXgVa{Iex#5SWjAz6 zdRq>K?)Z3QO64HT@R{q9c7@zf`-_&XGmqE8juuT6uw=r)vWa`7BB=z|gohOqACP=f zz}1keWzs5XjjQWi-N1(?KElT)J|TTdx=;Fy^f~u^!F^xiD-&Pi8--4Gdh`>^YQHt{ zEIJj24iV|-FP1{zkz@7F2ca+Ta{dpPHgVZo2T_uq&hC2iCqv(H3(;6GCGLo|-pipShg>G$kb)WPF{ZLZoFGQL zb!dU_j}dQ4ZsL_0%L$_p!`thzDU}^&fEI3Z+<{fc4mm;TJS8W4#3>dzLt7a0fc2;V z$K6%H)=iT{mQg*WgD@D^ew0DxnY=j)O%ip#wN~+)^cD}y+A98s?WuJF<{oq9fcf59 zB*L70Ld12iJ(ZoK65IPHbXfMK$eo?rmN?|hl8mdklM8r-FStT+=#MHtsvv z5;a4wgSRwFl$j-QUth9hqUZ&l22ZMz)6l2TC=vd1IhE~WGu``tk2rYwq~oc)^?hrb zmQU~{`454Al~5eE@|%^roLrS$kF`I9dLU4NHuog~$f>PZcx zCrGDAr%8>ZCrM9{nn-6zXGzVZ7ScJ=c~a(qR9%4+sKc?Or(rZmt&MWmB=#0rIg5HU z%kO!SCL>a`;s!3D9~Utqa?Oa<5~=QqSY_$=z9{p(DDtByL0#IV_j(xOcU5!{6%vI= zUFeST|A1@gk&M@6JtY?E`W&7Y3&qciUxi%j9-(zs9>9fsd&ed&cKjl?_&L-@kvmZ> bIcg;)^Rff+NwQTVjTfS9yK~%#BE0x7{S3wj literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/unix/UnixSyslog$CLibrary.class b/target/classes/org/productivity/java/syslog4j/impl/unix/UnixSyslog$CLibrary.class new file mode 100644 index 0000000000000000000000000000000000000000..5307cf4dbfac8858b3e98fbb0923d33da79f4308 GIT binary patch literal 408 zcmbVIu};G<6g)R2E+NoDCw7LgU?JGbRtYIm5JLoe8m!2XV@GyUkzZrr1NbO}V@_o^Tni73~-DfzvSoM8E+#B1(duSP?PGlDy9 zD%KkP(wCjsi*8^(>pT3mW};~&>z$BI>WghAcBU|cOPty`Rf?OfEUe|0U^VUhxT|^D y5v+ed_Q&Gp9~*=O1T%L6_q)NIV2%U8VF>DRfkSsQL*(lbmJTB~PY~lIjK2Wxy>MFq literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/unix/UnixSyslog.class b/target/classes/org/productivity/java/syslog4j/impl/unix/UnixSyslog.class new file mode 100644 index 0000000000000000000000000000000000000000..33295547f12fb16281271e8e6a222cf493cd3d73 GIT binary patch literal 3834 zcmbtX{c{!78Gg>q-j8fHBn{ysi1cF7+=PT%#rToLC<$OMUJ@iGHc+dZ&E{s~-rdW7 z08v!bs;%F(Vhb(PAD!t>1=;|0raEP&o#`Lazo9>M`kdX(y#eCHiJ4({&pGe=yr0i| zF8}`D-~JBZLHu6D9{j8sKf((tevTKjcqs>6g@ReRX{gXJmxZZf9u>K>kcE}SVh%5> zT-kD~Duo>R<+h+1HMu;MgQvnrARl2Cr_(ei|IVw}jx+LcR?00&jaPDbRld(j$k*iK z^(@}V;=Dj^tZdDCy0;{tl^ne7CR_T8H4NE^Csn{(VdK}kD~p%i&$m;xgk zvAky`7c`z3wj3)M5ojv(ObaMu?i^v;%9dk}ht*lrdrqIVxzka04JJuvs<=)zm0-bQ z1_w6c1Z}t2u0B^U%Sd4(FmVZnr0*FcDTjLKtYOvyR+G-DGCtPVdWBIm88T_R%29P} z-Ki9#HW<_Wpsqv5(q}v?py0EG(kju(z_Xmn_o=n?GHuPV)-s_DClX|4Bsv@o=jTmN zptEea)uJCd#YIOi9yP13w?yx9HP3SCAR8rZo2N}%AX_zkU$4;ROrdmgRN6_M9A&(0 zAc2W>GaI+_(HP{I=NkNSz0%>KHR6}x?TNj*sKDdvRqtDEFpPOS^cNVJzYqpkN44{G>Gru$4#x!>{ofd3!e}Wr}{I;d5Nj@P&lFtF_6#N$8J4w$*E$XxEwnUBVycgNnkFEi@N;xXz&}z7e*+u#%Ssc@DrTW7gpk1uXsm4Le z02=o#?>^qRIm32+Gn$w=9+%=d-F|0iyd-%MR5@zRQ=xA2in%RIiNih2o>Dj>lhy2- zL7WwVZG|JN!cB5@B9fxXiRjYeI8W|=fv&<@cR;BmH8OEV1PW_jQ+N8!I}*G3lV}fr zJf*P%-6%kyhpQBN`8$onh2IeqqBnUEy~%vOTPVvJ#OEVi4O55IfZBTY^I*N|L^C0FL`*S|Eb%Tg;+gS(Tt$1|GJfz!?7WJOi)iESO>8D1 zuc1R8Tthn#F5ws#or6l3@=t8;*wUpeW9u@uT|`C zy}+p^-*LH*qm$nUcsj~DjIj;}S@=V^4?kgZJ%b|3%=tK;#srSwIF8~uKBxG9glSYT zgR?k+b9e!7<3&!{m+%L+gskBR5eKMskXQ<}ia5+wnsTi~E^?14Ly2GV?=rCuMajM# zRXs)hm8vWB?3p;(tUsdm6pcp8L~3SaG#?)(^#V_%0ok8|2Fe6!zzRAw&VAX%)6|m= zsXP1QuG!tdSE&UokPB91LvoFhbsH)Zb1br>=8%ZwTah+nm*vx8`P3xcoE_R|8xfIj$-n-gVuu?1L_tP1f zh%_mA-<{Fr~%INCnTK=`B$RtTBk&G2yPTY>C*8_~Fn`%7-Ji*-*PI9=& Nx^SFxhTfmi{tpCkp)CLa literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/unix/UnixSyslogConfig.class b/target/classes/org/productivity/java/syslog4j/impl/unix/UnixSyslogConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..4e1576284b4cc1e2c642af85e81894474609d0da GIT binary patch literal 2176 zcmbVM-F6dI7~LnCW|A?`nx>#2I-t}vw2hUvQVZ2miWEZ&gjUPlBpK4_N@n8xuv&cy z-@#iibS+8Ol7-&;C_DtqeI}D>8e3p_k#o*`Kl}U6{`Sc~um1cCzznuE^$bRF zLoQ1im#wlb%eMR_fn;G~OF&t1>ZZVO*|N>`pj9>9M@F?tORntH*n+`E z_#GJ)f5-9!7R!#?D79Uu9@Kp6spapN!m{4J*K``QyCtjDZk7Vu+AD2xsf1=W|HP8* zoNkzYWNI27;YJG+eQmEuBg0gN-Ell$Ab-RkUrPqucU%VWD!iHM^%BMkeRxrPc-fs0 zPg~uqnIR=CF0;BQN?|PwYKNE_(aSwrH3r2W8G1G%Ml*Eu&cn3dGxiNPn^{ZbYWQBmMT9mBS~ zmcYUr?tHRb1+KkK?sC=hU8B~Mb*S|48T%E}u7@va-Dq*fO5w58Sc**1Aux5EQvV~~ zh-yBHk;5r$RCmo9#h<3^!Z$;`9eN{+d?Ve;Y2WF-1YG35Q=WfaNeXHVXTaI=D}nc* zNQv>RNR@HV(ns}i)%mr-7{Pt4cmPq%C7vN!Og@8BOm;BzI~@r^gMdR^&k`gLjRl7B zK2PUxiB<_n0DO#3xC>mycmzJpUHX(!q<-Vx#Y%;?3w^mtock#XQSM}vn-GJU7yB|3 zapnYygPF-+2WnnEHuDN5*_qDR$Gl&H`}lLH+s~2SK0qd?b?{EHgKP(pT(!uZn zM*bc^p9s;4K$VTSlMrQeFBqN%fdMPx# literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslog$CLibrary.class b/target/classes/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslog$CLibrary.class new file mode 100644 index 0000000000000000000000000000000000000000..3930ec8653969622690728f8a7cf1c44c3852ec7 GIT binary patch literal 645 zcmbtSO-}+b5Pel(5m6Du56&L&Vq@Zsi$Y?u35g~ff55VoP1mI*Z5Q3Y=D{D}k1`HL zH1W!zebe^6c{7uKe!YJHxIr(#Nr2M;XACu~lNaGA=!ao=6*2^gR!Sr;z&S%bqUZbR z)G#zdx;CRcwpLh%r+zrrCglsGr$yrAQo537@iOMNw7E`iGcML0tZ^p@Rw{0&q28JD4yYywM6`D7y0AURckNaqPJiwvHBeaOQgJZw9u}9dZ PbAS%&#HFs$tu?;^PtLoB literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslog$SockAddr.class b/target/classes/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslog$SockAddr.class new file mode 100644 index 0000000000000000000000000000000000000000..aba04c3c090e78b2d7ce43c912fdaf43a306fa14 GIT binary patch literal 1081 zcmb_aYflqV5IwiM^u_Y3g6|igv_)A_d?XMfMU0IN5Vw$kiOsTI%hv5~vkzi_mJiez z;t%jg8P8pcA^1_7^v<2xnRCyXnV-MD{{S$L$9d#1l|vTO^0=ADEzHQHm`4d^8Jo@E zP6l%VL&oM>V`I7gqG42bRs}?ru@&D7Bh!nvOgFX_V!8skoz++CjmmbNNvYQrfqWQy zjkjjUaeFK?1hO*FHKRR&^pfK_(GvlsSlSX$SNx_eFj8|odoAwl+Ckmibr~tte9LsV z%)pU;Kd44~PDnVzx85x`n}L8<^*lRRam_Ha`Q>HJ4_bOR@SCv}Ir~o3)7$30sfWGL z^;-*V-RX2)J@%aUdPodA(l>dRaCT%QIn&43i&6)pvA2;BA1~GtDA)8_x)BAA*IJYc zGSqgIQTRK7T$e1juQ+e`abVfc9jR~p^uu!!UBeli)i8=N4F!y3pli5`c@6h)KZ6Ag z5AaaKu>A5!p!(m$l8@zgbV||No+;(Ae{n#bqo+kvQp=7iy-4<3EtcfK)2{8c5s@HzI0Xkr(c*M&mt9- zk{2e9Q2H+r4_C>71H$z`?5D^{{sz^20qt7xOS2f*1)$p_!uKarK z{4ZW-Ya#6?piNz^rgB<6p^Z0z0#oJ(4clR>8}=`nc{+q{q~8HSJ6|hBdNw zEUlNyM%pv=lWB)gG&g;KV~I+02mCWjE8x2Yn&rXin*>+XM+CM%x0*l_bwrBNn2bQ} z2Hn)%w*_ia%LfIbeO7@6&C2Sgw%aS^G<(0AGq}>2wesXmC3~EQi&1w}C%?VVjf;pH z3{pJh!GuIbN9m`iyCyG5Zp-?d8mc*x_FdbjI_}n!d9Ccym6VW}nh;YwZ!re)F1;@) z54`^Z{3QJ%g;Af#3&c*?x=V1ism$SCNnp&-#x;ZbOPb@TBixD{?j^R|gsb&>#iGU_ zYzizfbt~OFwM>DrqTxBC67i_#7OWGdK>dj34oMZfwjs6rsfg~$Ij*hd!^jG5Q@Ubn zu4kJSX&Y0|E=(G#1i@VqxBl6sk(~j{v-4WNE+eh!;oMj${jOjwx)gL`g@TnxD|j8N z6s*RYI8G@zjWYsWPe{Tb)Ao6$tCzH?SP@w1EA-PaX@*KaLIFZBfV!}i{`Q#9pHqo z1M7wENQ(Wk%O|BNHLbV}xVCPNbju`5F#V@$;ymVm)tlidR_44_N;{sJ9y8VSZk6v3 zlW5%|1Wvo`*U#?h;`Zdmh)yS!P&1k3+)vQ7qs35!2nFm_UDnBj!{^g8gGto!--^Ad z%u^xu$o^v=<4P!Y`v~Uxq(4}#`BI*+)v~~X6zl$D>Uj&XJmPL3HI_Flhb%->RDwnP zoms-)tQcCb3@HdK=PZJDL}kt6I4aAY-?Q@hJ&PavdY)xzWcvnZ1H2>HFKE97(Oz>C zk#=ztHL{7eM{Xi^gPReoW7|w+Kr02WrI0TEa;?K$yvYwx0wH({>p5F0(>_#Sp~l}^ zbsM$UG2<@c!;N*fQ2%H9?}%JSYdibsBocGca2v{fG)V1H;;1TaK`n)Lv)zE%*o67a z>kjm=qW4WxzA9ACcaO>=zI7&*M|ihQYMF5#GilY&n3?ra%=S@CV$Ka8U;_=B6`C4o z+{VAfom|aueFqj`7ZzfVud$iuW+8!%c-z0*7V6$aT~V&YNdapQN0Q^eNn8#4ae|0N zenj+!gi{k3-WYUqgKpj(G(|z$IgLerLVe(ayJ#N1h56Zz@Xk%V6b=_mqJ@i6SgfOC z5-;CDYZMz>t9PqBuBR=)KGf0c^%x|F2N@B=wCE7=A0eYhSs#yK2swlYE5!%{A`+Cqz8^`GWK1zzv_AS`TURr&bvncz{(3E)lBo>C_=#9?XXxm)@zM}Kq z9lR37P!($%IRuUqt3l}&=An!x{>--!O$Ww(JTlfPKg1(P{X`+7xf9#4oj6+1Nbl_+ z?y6___dOLK!}N?izl_+DPj*Tb-b|m02?98c*Ko#%6Xd|M|Ac~&k4{L+5PPYxN<@W& zJ6IIK&?8gsELk{5kDX`aUtj`WoThH!Bh>A}ZYq&J=wvU|MZ|Bi_0zc4U%50*MkJIW z7~Olrn_d2SKvZoGE?)I7$^_u%6!ik{FtGUV%FvRE_TyFdjT|+wP%W)hSUnb#Ddk_e CI*0@S literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslogConfig.class b/target/classes/org/productivity/java/syslog4j/impl/unix/socket/UnixSocketSyslogConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..6aace1d9699f793593f116620655d0d9559d27d3 GIT binary patch literal 4047 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 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/SyslogServerConfigIF.class b/target/classes/org/productivity/java/syslog4j/server/SyslogServerConfigIF.class new file mode 100644 index 0000000000000000000000000000000000000000..3ec69f7c6d48c92aaa1f2084f00118a8ffbc309e GIT binary patch literal 1221 zcmb_bTW`}a6h7X<0_D=K?FQq1C*{&G30~L}+8QlWB_=XJ+M8)i>MFG-+X?Ki@xTw@ zMh;%;39cfYJ+8S`N$|Pl7gUTgf*{LU*&u62{Z;@M(oINDYOgE zOUZqyP;%Mpg{4BdcD%4CSmpYiW;>Kkr8pQXMq^7oB+$mqPNW>~&{komC3|0Sskk{t zCFC#0TF4vZOqg9N;*=>odV6-X%<$A7a&7Qn&BCT}W@7nSe4xB+cMs#JIUjety`q68 zjpMp7fq^%aD)En$jI)v9IrijRi?y}?#l+Wk0)BlQb%`+8DwNw?AaSm10)ZF)Cv}BJ z=d8Xjf%P)@I!)_w^a^K&9d+!8aL9PBOtE-}8j4q>9M6d`I*9~!z^5#bYD$e^YVkt7 z`8Z*t!uLYt5A3sG5qGuJb&&F0Bg(zCIVA|8DXj`?X@!c#)R$SWL+UI&gR$5>qh%lma0**Zfj$U zO(|=34Lg}eoknp?cFS*q$hr2;wgH*itIIgiCLljvM-L5G{!>-CVRuYc9h$KJ|H{7{ w!dnb!R8`2YbIF+}yhlr08A8VM)Yk-5m1qbf{%T>p)qk|-1%rE!I;>@g|0@J)RIcc%uvIxx$p!0DC3=> zDlsN5I%nqGbIzUHdH;BQ18{^x2YU|o9UL%}BcX5k3q#5E9?lqQbPo6^PGY@aD7xN& zIJL@^+<|w;;E?cwYr)WTz2Sss+@I?>@eOxMW%4Y`E%$fT*ehfoicBQ5C277jp;xKW z4DGMbgij+s)H0q%dF)cq$zxaRCb$98Y{@J^mj7 z3=J!_x4wCth!M@&|0iylbN<9-DCiPp28IHCMS9J8iJlH?0AU%9#R}FfR#CH9$A-nt dyuOv!8`!pd6D^BvbS&=V{I21tPnXsLdY`5$kN*Gw literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/SyslogServerIF.class b/target/classes/org/productivity/java/syslog4j/server/SyslogServerIF.class new file mode 100644 index 0000000000000000000000000000000000000000..f0b1a48e0c34c79c322e68bd0e18ae783eb7f47b GIT binary patch literal 616 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 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/SyslogServerSessionEventHandlerIF.class b/target/classes/org/productivity/java/syslog4j/server/SyslogServerSessionEventHandlerIF.class new file mode 100644 index 0000000000000000000000000000000000000000..560accd759991bd2b813ef884a9e58547d116260 GIT binary patch literal 829 zcmcIj!Ab)$5Peg(U0bczpOE%q5WMxGNLLGm9u_=!+ir%k>#`|Hy0kyzhj{P<{3tP- zQdIO(v4>ArKT&!v7Fx+=YO^Y{ zYmp~aBFx$pYJQaq!@6QEV(-V^8Arp3Pb%4pSfx*FZ=}=?c{tbvilm&2=`82e4hc=J zxU_`l{?F+Dmj46VsOIK68axo%yh?dtoj!!s{>gd`y;P%ZT~A{>q}xK7dPs8bR37W@ zJF!~ol%uR*!ui*M$D5_`Qr#z|ELe}Di<&;+ZukB96^_vR)MK+cgzMeGzmsec2n}}* e+*b$!LV%`w5LyVmJw)5v4vt&~;n>{`bUy&%GZ_j1 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/SyslogServerSessionlessEventHandlerIF.class b/target/classes/org/productivity/java/syslog4j/server/SyslogServerSessionlessEventHandlerIF.class new file mode 100644 index 0000000000000000000000000000000000000000..7a8c8f157c4ba1b5f46f07ca7f3e3e57019b1191 GIT binary patch literal 549 zcmb`F!Ab)$5QhJ$ZP!){K8AWQ6ukAKhb|TiJp{b3+3B)tNJ^3}_8oj84?choRm=uN zJ$R^i2*V7+|9>-+_x_k(vh44GC zZFSuU&#q-BWXfeq7Wr(MnhXaat$N~cTb7Q!pZ!5?-jPJfiwDAppA~OHZ4F`l-)IS0 z7p4;PPnTpmmUinD=e1_S<@Z5l94WHs7!u`OVM@(zkzaLMg!{vH_p2n~>nvhk)UA3K7!@W3W)CuR=BwBDQj(LGrS2~tiT9b}z zmF*|FSpl&q&@@xFUC*?=HM6uYqp#)j{=XkLe<6@`5AEWEjU8F^1lpH(%mXu1GVQI5 ze>Ncyo3w1pyCV=D7+e#G%#=5!K+Cda%l!WChICfVjS^4Vm&-*4HW{A#;4tECTdqK& zAYFxrOCx97(wQllt}D4+TrN9XnLVexxnK0G1Is(iXbkS5TPkmj?qta4Ksp&~cdwM0 z-f%s~EP4fPENIKM%F~3}U~X;}%Ef1rT;3Y+$=K4%_-7Lee#{N*ZFOdfu_Zm@Z4FMe+FvY}beRkBn+b%pFMETQKd-l5}$O6ZL6O(39J~!-~15 z^w%qtL7E3`1Cky3$rzqzwRj{e^%ISuZ)j$e82Hr-uK--zl3#PkGCI;?f!9Wg+ z29~fK$BKbGt{eCOHw`>cHy`4WfyXGY@y@Pmp<4C624Ebk0t^3F6R=D7_F4Vofx0z; z&a0~WLSuuw);Cm#-JWB+Jd=k7)lO}1bOVoAaW&kuPr?eCL?Bu$Nz)N%ES7E0v}|`t z9tw1xgKF?I#$q)I^q*%v58>1W)xvxHe1`e?4WS3^=m5VKde_OkGwEC>c*Yvw_zrg& z&VqAv=x2x*+Vv90m_F>oyIdQ-1A6&5xW0-$j_R_F2>$`SKOwZf@_K0a6~gO$=NOTv z>C+#P$fr+7etSVMF?8zS-MptjgrK6d>)V604iV}wqosAkF53BO5K*nJ;eE!WkhmVi zp3{4vW9S&sAJD`pc7nLTkvOUbXx3U}5N83m;iDQl9aTC57!00#PVYGHjww3X2>Bc% zk&ULJf5Hfusa<;H1Px(4O+`qtF&pEYifNW{K9%MJY5wo0W}juResrAUZ8T$oOee{H zid^nu6w?~iD5A7=Q-@)$2%*Y-Ea0xr(iqXojNt}-!-Sow=Hgpg)Xlz1E{Hup@&_7- zHYuRek<3QYr>RJg5S0q>_p+XSs69*tFw1d{X}^zFET9XEO!<X^dsuCS`Eg_)exOQh!8!L zP9cW*kV*Ax@jLES@-+W^kh@4Kl0HFm2r6$Qr$^b?h{_dRV`QyL@Di@*+2`M-CH$1u zb^iJBIXmV{TED8MsEL1!sL&BwqB;p$@+!oN3Q8G2SqY}N(rbN;t9}|^p@nVI`Vt}4 caY6&|JFcHDV>}DtV*&&9;P;8ixQvE>0fTH0<^TWy literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/AbstractSyslogServer.class b/target/classes/org/productivity/java/syslog4j/server/impl/AbstractSyslogServer.class new file mode 100644 index 0000000000000000000000000000000000000000..c9e890101ebd474e057ff6c471fd92f7a604fbe6 GIT binary patch literal 9368 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 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/AbstractSyslogServerConfig.class b/target/classes/org/productivity/java/syslog4j/server/impl/AbstractSyslogServerConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..c6799e84d3290611019a3fb6eb627ca91c57fe8c GIT binary patch literal 3073 zcmb_d?NZxT5Z#NvK!|`1p`DVJByCe;NSw5!rGca&7zb0Akk~*%lQtJyvBe09kz_JF zLf@sGX=lo0($3@o`aJ#J=~>CxvXG~lN&Vwq>1y}v*|WRXfBo~v8zQf$dQ(uU)|7Tda|LC}`|?QU4QV#= z71!3y#-bqAX|~+D_0rstI&4O?Bh7Tzq**r*0MUG(ma7~2vhKL>NVgmf?yZ{JvbB0a zx)Ka_abB0MR@D!*qGcaQ*VXLakPr6uwHgDA0-zwZ1Iw&7ZB5n%opZg1O!!BRI@r_fs@yYhk||p?=pmsB-rI+9x2c2v{jy~@ z@`tun2VMOL*m+L_=h!i<#{7OBVjgLBUOzZA^2>XUYs;Ej@jh0(FHrS`&N@vrwB8Sf zbP!-XI}=cKg%4q@z=>Xp7=#HFC*or~yUWqio@a0Wb8}&k!qd~+ zIi2}o{0Qrw9%>tNz>H6)H)0wQ{psrt9oS>+(l8HyiDyfUq*SbyUDJv>kKJ_tak<7b zrqUJqOi*I0TD-cT(g!r9(gm7?blwDd&A4pa@|dp`l|H18RGOxXDqW(>Dt*jPpU|f% zs;i{Y3tk#3HTg+r+|~bOurV;*JJHun(5<(F4$gspO_Ykb%DUNcV(2bRnxM$ypjRf* z#9;>B7$yDAgMc+dlXm%3L z?U2>mp)7XBLy@p%@%EBpc*5UT?iGn#X5fTkxe1D&P%`%?rJlT^!4n$F#ZE}ci4z*m z;ftDs)yQvf8lV}hmqCs|jtMCslLn0o2+85Epq#S^n}dbw2g3UtSPQyJ*KjH*PuJUI z^4OV7BKJGRe#L_yAn6@u10V?>1m`#CbF7@n9as-wPv&NkM3tcVIZhh|^XxdGY<(^;Znx*edSc63o`k(N9_;OzbOQ8IWgJ4sZ1J2#1EP!OVDW@<(VW~FJ3l9V7Bs)?i`BwDk z7bA(NVItK?BKK)6B8%a0BR!6EF46j#EHGNb;Vhmai)VeZ;5&ee@NKjrY8dM|uw)-B wzQ!1V6>ooC|sILxtJz3NlS}U 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 D2Vh9b literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/event/printstream/FileSyslogServerEventHandler.class b/target/classes/org/productivity/java/syslog4j/server/impl/event/printstream/FileSyslogServerEventHandler.class new file mode 100644 index 0000000000000000000000000000000000000000..c4dcb20ae70b19da1e89190c1699e330e691114b GIT binary patch literal 1326 zcmcIjOH6kMhFs~zTpbHB+77cV` z$v_&*1`L=wuIX427z$-zTh6WwLfdnnZru|Q4+Z)+JU5IiH`=wFy6pb;=1cf)efh1x za5<1xBp(O18xIuxZr5x3 zGI(O`JFJWpyfTegw8M3~*!#kEURQK;iO8?W209o-QaJ7xI!U7Cqr+HCu*;00CF z54=jf9N7&!IyB=k!o$$;Uf7cJA%GxZ9ce#Bnhh)|$d{$5^5*A%>LZ zc?3`ES@a>pXFpdd4Dj5>Ir4pkmDkXCf`OSMh*G|Z)T1MGl@=$P(6*1zU0Q0Q=e9PX zy^p^h<$Z)-fNE(BVid!e=KTySt1TUjAjYZ-L5P hij`lOI$e2^%2ToOOpE!Ovg)B`OP%O(g{moB{Q(g{Mt=YR literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/event/printstream/PrintStreamSyslogServerEventHandler.class b/target/classes/org/productivity/java/syslog4j/server/impl/event/printstream/PrintStreamSyslogServerEventHandler.class new file mode 100644 index 0000000000000000000000000000000000000000..3c79c0ed545f26de5abd6b83cabf704a8c2b2c4f GIT binary patch literal 2868 zcmcImZF3V<6n<`+WYct8N}+{1iuDCeQzRBkr7c3CFAxY62`y4YyG<@(>vp%Z*|ebJ zU-7Gc)EO-*Gk$ZN@eldU@ws=mn{_BttkW;M=f0fhJoh>0+}%I_{`EHiqpgg$NIB&ala6#aBVb>kQO9JT`uPy}+Rcu$@Y^|?K|BkilaHg-~ z)kwx7C61%XbnwV-3anNF}7CXNj9Zlve!49lH8PT zz|CY95>B$LYLBYkKBqQbwcNTReX`Fh^3=orl58dlFBvikSe~C!M>IoPVGx1w{UI?C zP1#hLS=f-StW$-3atd?d%Ai#BYG26UQoZgId1^RZa4fe`T3B6^wSX#gHVzHMYSgzYvcX6~U? zvmKTz#d4^YBhV=y*W^aPvY`bJ1pH>GpaRN&wUd3w$?wa@n_XK*h z60N{?O0!IuiDle3@hKh{_{_xTSTSMYfr(YD2pnt67UuGD%XaG0C%vys)IecUUk`CK zWJ2P;frlm`p2=qRXcO#FAesNI;mh76Rz z?6pF4!Nj7gjtIO^QGug7>$(Wzp6MdMeB3r9R2CTBgOH989&eEu)(v+!fwL2`zfewI zdU4Dg_g2FG?AbAQe6rRC?_Xy8y<{syuFs=Im7=~UM7lwltp>$7qOU?!U27B1YOgF=p;Z7o!{h)3PCr#g}3=umV#%E<0RgRz|V4C?GkOcESEswHiU>F z1l~nKLky!BK}_@ApQ?ENJSVb@CZ)v$xPsMg!UJA=ZLU1nEnMF z0)L?U8PfNjBJ(Zs(cCt&lNn_j0zV@+nN@bDvh$Nh@kgYdp^F}7U-ve82D5zh9a2_C zS-r|KVvC-K1vuPB-!_i4Wf(w)G=`aiB1w+m97%4Hrjq4$NHIRr7D{-Z2Ow>IIHl;8 zKAaL}i=Ly*&Jgb63_c+4DO|@Gtt?S5;w&wd@^O3^iBP4NivCi{3^T~`x2Kvr!IOG5VwU*Z7nRz?&{5-$!u73eo#e4y;OCU@RV+zwH1mpn&f0OrrTfxGaq#2d#4`1Lw)#@L&qB8oX?M0i5VD)5%|%BWO3VFT z_fXoe;xOSz{-e^$Z4icP^(JAgVOq>qFlSERW3ui@rG$fL@=@KBB$A#1lULfMj<3}9 zG@a~jSv$ygkSNnE#inOla$9+7i%c%DxG%Bze~R10`h##_Ae&Kzs;UoF3Q zS>hneV`A{+gvU;V?%YeqZzQcHOf*79nP{L6i#Jt!Fi~$}fd@0kV@jAo9tE~V_A(d_ z-wTvEQsKxv`+gN~K;N&BIp;HBg!epKFrG&URo*>%ozXs8e1D0dD`YSDoC)Yss8iui UBY4SCU!QRp!z;Fg@qnE83+a&UC;$Ke literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/event/printstream/SystemOutSyslogServerEventHandler.class b/target/classes/org/productivity/java/syslog4j/server/impl/event/printstream/SystemOutSyslogServerEventHandler.class new file mode 100644 index 0000000000000000000000000000000000000000..46b616e89d39cfbb438b2f3f9418f25b1fcb08bf GIT binary patch literal 829 zcmbtSO-~d-5Ph}m7sD>BC?E1AUd*lsCnm;=#0yGT-6+YxCR~WkZf9*W+f90UCgDH$ zW7G=?CjJ1g{2xMfhr=E)66|EUx~kq(y?$MPt}cE9c!|v#79$Xrrm>925h_@zVU^Iz zq*WsAOPeX954!IN^nuXaHac@cyS_+sSy?J(zFkHeT|#wWrErq)vEAtzJBm-O8Ri40 z3gyn?6H$mbJIhitdUX1iDZ8&KBYe3dA2mKrW9b<%d8J+E_)23> z)5-DY+)eVGB+4|S#N>7$ca*30?4N(U@OluA?xxdyc{MPHRt;+ntYgDFPgslpYPsiS zNrEhY6N4uwJa#Jd=teqzBa=JALN8>Li6`o?c+2fu6P-Su@?chYObIKfqQN#`6fF#k)tpX0(sipZ~{kvrV_;jm@SML=+Vj zQA9y!9KSl_HwI>GV06aun=_7o#y{ZroZZb!(||9-m%DrKJ@=gFJm1hE+>WjH0nX&K%OaX2HxSsC66;T-e;CS-3igcuANreuiAFfCSQJ!WKb zUM7hU8juVjg|r;X$i{^LED4&G62W(~{K6XS-J zHPfl%(E$Z@NMT8TI+eBcls&E|az^dyfsOa>{ZaRwLX)1!B+N`2zOXq&T)n2_SVjyd*Yj`5(F5qKa;XnLFoYEJhtkA#tm+taK< zRH1<&3+NSARnJPHqit~ss@n7vf@7Zq7R`s#69LVUzj4^3Dq?b#? zTPBW-Ze@+$N;&!31f((*8XbcpB_Rc!1;I{%xms{!qBvh!M#13Rq>&MUlHQQW%9W+4 zQbHa~XKl)sG%O0%tB4Nb!M6VUkC8@IojEtpo)}%3Hit1ZR;1-EV+``N5R&4R@)$k(10lcT-8s69N0Y21l z9V7Dgk%l1&uNdiLe4^n1dNka?rvcp5@EJbWa0_2(*oWH+D@v6s=BwdVf%T=}?U%Q& z#PJ>6RoGlIe;iv1Ba*_?tCFz!wZe&i@cMt-i9+9h_PnU12Vd*kfTnJslF~-YQ|rFdx=4U5i<7 zAIB#Cn%Kf0H?>%cR%`{8!C4KShhKUF-~G}aoF_Yk^JJ6YQ={!p{wPw|&Djmw`T5)$ zeh3v_UNaA0Sk1#PL#+&T;g0p&^9Y3VsDD7i8oa=9GwL}?uuYI3HcbT6Od!uNcnia} zGI%E~!me}d!CuZ7hE3)rhL*Q|c$wbhtqc3%b6|CQuM<6i3%U~S7ISPj*VDyVj1 zBU9eOlm%6b>$`}mRa&2es@1_#!*{kg56d7?3gQ*vA5r%kLg7aU2``-8=dw#kqvLW9 z0!*}#sYw`Nn#a5_3a_BobJ@#Nl6o-Q@hckWti)`{+2|&}2OKA>T*D&PAbWiu-T0-E zdhYIUChq!)Nn6^I$CCZ)YQASpW$s&-M`IpMQdya=^PkIO={z)Yw`}=xF8T6U@h$45 z+P)GHx5T|HZ$HaBKmrG;qao55MK=x+#BdqFeh*-Xxev0i0+8Pf58zD?V9!E;n<@bM z7Xoy^`AgvZC2$)^G%!kVuM^x+f*T{aaRxs@-cFVQ>nQ@;Qv}A3kq7Kg0u%YiOTZRl zD6I>leKIW&dYA+@kA$~Vhb!f>aIZFxRr6TwxZv`d0@XjDeuPS1`+#9PaTYo+imRKw zSil86`6KT}M9xS0NBuP(b6rdcVRbrqcCvA$G_wWwp9S!OWDQe0vwF0&L@ zsFSM>N>{+Ui#Xam9Ey33cx8z2DR-roIDDl`Rp%^TbKJO>sn&C&So>;+{gsEWS3P`$ zvT^%gdF0y4!#AoPK1!{*hflKrLh@=V;n_#naDVt`w478*rVp{{z5_qNtGv;xw%a9c capg9GxLf2W$et0!F~@#&F~#F_U4!wz0W1`2ZvX%Q literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/net/AbstractNetSyslogServerConfig.class b/target/classes/org/productivity/java/syslog4j/server/impl/net/AbstractNetSyslogServerConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..e3a24d8bf65341b74a1e296193a6b4c092c0f90f GIT binary patch literal 992 zcmb`F+iDX*9LB%d>?Ru1Lt+owRBI1H8o@>IPAN!KjD%QB&HW}Fw^O&fVRsVf6ZkS- zC|Cq9d;sr!2cJXyW|C?(RS>+Hng8jV-#5(XZy!GaxPzNTc(`#9F4oPmQNU&aTLSZ$ zOjQtdWtyoZe$jj=Af5`$G?F;eL9Dw$G?d<#=U<<_+I`&=a1WA93shQ%!6@*fAP)VG zPE{PT|@2gnp9f4eJyUR)=*_Q%yEfvf5@Te!#y`UE{Q)wlA-X4&F@g(W$ z1C?1*q)AU zpp}=(@D)O-pIH2b+V*({3fXDHVr{x^j2MYs>ypOk(@czGx7IWb#ZEFz`|`0e?l%5P zblbQoVGi>pTtcaY8O#d&SJMKI{^1QzX{R60UFVpp0K^_GNTwvtD{3WvU>>7OT z9&5D3walo&9>Kj_{{T@JCvfUz$2mdn9g_|!TxTf?4!F2XxdpDEpdDhg$Vgxb%M(GL zyQz8g_i*0wFc!(%u-oBGzJ7}&KM{&HTP6FdRahE#O%&K~J(`PG pP@QO<1ghOrYTRrINdg>ec`grTB8jB*T!W-yE)oDSm*hN}?Ah!A-) zj8Qx#HqNRTQ!y?UpBD3T6*wP8EiQ-y7ganX7Ik4^LdYakBvlwHCKZ&shBIq83ikKg zPAZyl>|{3KnX{&MH9D=&>QVQqo3>N?rlUE*Xk5Hz1OK7kYmkdwA`hI!9GQ4P9 zE^)KMHC)%UEmuW~vv_`{K#N(H;dG~Uml6t2m1y0Z$)uylCS1?a6P_PR)1qpD=#Xid z-eCnFHve~OOVs4YM0)O_q-9h=sM}5&3aa}}%NWegOc>6HK9S~1O~0Mc)1$g$ig|u9 z;%v}DO|f}{qWti`rjI8bKH z8WtnoRia%#DLvw-Oq{?3q1WdaGVSQ`?Bt~37|CHnPZ|y_hSKCmkRsD6ty`&R+;dDT zCD6DYx3({*cf_1A?5x*wC1GSdrX3{%E(JF)7xYU6O`9Sc3qWE+{$16}=~SSMD+tH! ztdlT$O%bk5OZbu$?h#luw4g)7Hf-0h0}p9vLbHY`mm3*LqtbZM#NN!yCwGcoT0as4bu`a;M>Kyrbb=m>S+g zhk}cx6_`~gse*M9hRl?qiD@Ij6s;*P4QDMYchCCn1IgbO8wHhmGMS@A!G`ALY1Sof zOZ75t6|7Aeo-fYKq~?}l`V|v^>06)I$&~S(ka}y2TlqU9tW_{`lA^K*JbA54@6M5b z={+m`l&n1Yk~@?!SQ&iW=WZ$MaN4j^-ju8wF$Mcdv+FMwv0gGvvbt?+(&Phjm>%7~ zmfUGsb8^fZ-mzrT;aep5&2uDfM~qE=ht&6!X6YaDl{G_8BxtLty}ez*C#60~ei{l6 zpxKk?P65i%j1aGBBbQNkAy%SfYju|y<%-EihySasA z*z8Y+C3{SV>O3opZ;OH}`3vYPIIDRPSMYE#34QS{RAhPg!*pSQNu{TF&&!R=Sv}2U z-nasw7QR}wOYUp8EZ+(~`u_!XT!cq+7@OIAZ1}MupBrrFNAgziEkh6?@wW0)IwYP~ z+4F^EAK-oqB5Zea_BH3_?2komLWwA!BOscfXhM+gvL5U--y0#9%T)o zZ|6|eDf))8uWnFL1drkXl^ww2vJaq@vpuL{yGsJ8B$Ty$>TB^Z>ItWjP<9YVgpwU- z!%<4NQ943tg5s>5y%-7biW~{I0&*lA3vzWY&q{Zc-%!Rs;Md@x+bAEq4RwrggY&4k ziOQP@546ssYOw8l)Ce#59}wFM(71GvPOZ6)4zcIy8sQ0l&yRHnc8aV@(~!HqE2{I)Zc9w33Mb)RqNo&d+Ih3y16;_=|%# z$WZ{(m_d!~U9u|X*U*4Z@e}T_&qct(7ILzevwdWJKUqIO4iA#sL+E0x&fo|p$Z-nC zc|J~!Ct#rm8IE0?$A!=~2cy ZK(r#2k28-T{ol!7Z@Xx-k+`C${1Y)OHSz!e literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServer.class b/target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServer.class new file mode 100644 index 0000000000000000000000000000000000000000..6b8ca90d5c61148a3b53e2ee8144b2a6d8103036 GIT binary patch literal 5647 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 F_#er^JTm|Q literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfig.class b/target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..beda12afa8de0db629a3f031295e2b2ef3abff04 GIT binary patch literal 2518 zcmb_d-EI>{6h33GZQ>e2Fg?&}xQm2|63Pf#=k=-5~V*`d0C-An{Pp>2<#zMovB2 zc4`eb_4#Gy)9a7frl3sZ?Yn*>f?E-@9jEfF=2wwt-}&oKCGwhX*{?ivqfpSf?xi(% z*J*lwfY>!b=@qZ;MXQ36=KQuGW8Hu13hFO;b@y>&f5#0rot+w121+cb zqY*lnqaSG?M|n1bY=&q!M;G{O zilznKJCV8zdUPUrRR0M2zukCeCyWB85^38J-F<@OiuY*}w?9jQexMZnL^(Q*?=yHd z64Xxy>y2-NC6^;qmm`G7*biTn1$Gp(KM*4@j#~ecu#$(AV3TBHut~kaW&$9DUmA7< zi3b3m2jC#=5K@g&0XsRBh|bd(W(+bOgX|$g0&C;FK&-+crQ1m3l!13agT%SVB-*gb z7^5LKw-oRgcOu4p0iPr?P5&pZbsh(9gHO>Zgj~>oPXKxnO*cP7R?UINBt2|Dyw5||qBd4O9GV4;Tu ziU3Q%)ld@5##CNmZa`YIXEj<>tg-J(GKYR6x}@Q=2tGFWT&AD#pUGWlDU4QGOzg5K zz>PWa7hjDeR_73>3bcrky^K7a`Uj)x`LtYHl9^S18?F8}X+Dm%)mc9a$ma4J< literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfigIF.class b/target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/TCPNetSyslogServerConfigIF.class new file mode 100644 index 0000000000000000000000000000000000000000..299025aaa799f42377370013c9c64d63432f8c08 GIT binary patch literal 631 zcma)4%TB^T6ul!A@PVTELKa3>uyJDI%3a%(SQRm}Y21-o$66>I(oP%sH5Yz>A7#7@ zjgpAQ#XQc*IcM(NnfH&^Hvl+;MhOl|P%ptDf#Z&P-&b|pbd0{$)vpcP>TAZO>X_YL zU%Nqu0MQ6kbRH$bjfCTdDJx(O5IFhE+%v8W-JU85fmNRgI~XyZ3Ic^@%S0-fqm-uE za%M8k^@bt$XM!(K!+?(aqIx38n8m#z6A6JDX8dFu3$z-0cC&!T@^rjUV}bKqqck;H zj>Xg1W9=Yh1deR|?v@E_l3;Zfi!&BuPo4tbY@ZI?%q7s_u}{Y_e@v%U24X^|JWZtI zd_WUvqQPh!(ufHvyfOVflt5M5LpSni_hG<1Y~98Gj#yM=5g!tka1?N^g96LAFXHno s0e%K3&*2p)E7*Tn1Hg41DstV(@n(*zIo`_gHq@kU2X^J}*pu1&pFbj_a{vGU literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServer.class b/target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServer.class new file mode 100644 index 0000000000000000000000000000000000000000..9c8e4c09debad2851a46d6f7ff0eadba755c2310 GIT binary patch literal 2029 zcmb_dU2_vv7=BK>$%bUHn9!IMr4;#S(>6=x!%CrurG-jpE1Rh^jyK!w61Qx#ardMW z?ws*b|A4#(G)r3-p8KyVq<9(m^ydUR%&iVJhzyAR+hh`on%!I@2 zF%(f(p%&lKE*#4gF>&|Y+)!VkzrPa}cz|{?-(OlYCv!xLsjR>|N zkPl;WOxJlz&!>oNTAc%^C9nO+X$fo|sqgsI)fL8&du;a%>G@IaQ97>KZs~^fopy`* z6RCc~41ym#f16=TzZ=NZsJ|INEI+aAj&!_spyCUGa*Me~SsR}9*p@4%MVCE+iOH!( z==4ccuR|b=pcI$&faUmG>{KiMq%gJpr{QQmY~ zZ4E29D*zSuG_2yThA(lS#fb_~XT#Ll0`;`sDjFIdU`@k%Xm$EKZ$oxbn7QtF`s(_C zv_gu$fpP2aQh?VZPA{L0Tp$bX@3ZY>()#)VzD02k$oN>1i@SWn?C-m#%XesWGV1-< zaD8jXw&cRpH>B!-X)lmAZ3=-cH+-*S`;u&%A2duDK5$ebi5YnytkOX2X|D(zr?ffn z7>vHM@8ixzZ5MGoc@GbvI_XODJN6^9>q<=U-7oPo0EQt#dU7mtr*kHUkg5F%@jDko z_<&pYc&PRVhF?HwO#g+9z=N5WC>OIc&!9d- z?pNfC$7Y@*|24G*KK-+icDAq8W)tmkf$K_Dd5KCfTUAm(q4-`^Nf0AMWU84Mk?A8& zR5Kx>pTr_Y7+i(_*BF!dkolj+#~4QqXZb0f!)=_$Jxr47HEdxTJE+6QCHzF~&$t{V zzZfT&B(LE|p7RllP{LE5HqHXf;ai;HYMAHTWSz(9&u5X&a+RS!a4+ahp|=Zh;rNpZ qu2|;hc)v0I8&`4J^O5u#vGbAla*Rs6E8JaVykh^Z?(XFFX+GI#neKXvjCzD4qhVHtdzQM_Df zGm;v17x8mV!_xQr$A`Mp(hg1UMY{u54a7K)l@fnrxQtp&+vzDMj@|8dxG^yJQ1S5G zp=;W``$q~A9q5i?9G{qqrE`UMP88QQ6;*Av8VCD2S3OJBGei2X4Ux}$Pv?7+lndob zRMPWq(5P7c+eW074}|h_&j);cZ5FnzK-sde3Z9Eo_r70o%FfppU_X_giS__#DxZc> zB4=5(`%XvSF+|PR{!yQrsBne~RLoG07BX~Eh(#gtw7}?GTf*r1`FEJn-Wh_jOHjoS4gIL>@)c0G0Ku8Dv!M+itnwczqg_VSY_CvL69Y!RQNEg zOVzK$s_YBJgoq0v36c1O%NSjPEa5Ria0v~aLq9JdNFLhD&}K$KXbCuk{Z+a)en7!0 z9!OL_Q|u!)qhLu-xfF0tOq`c#W$e5S>ll2J)lHE3D6*$r2GEKZp)|4@M}WOo1M%=` zBuG3AvK|St77Y>)gKPlg)(jBQ1Oc)h2_l6-Dv==9qd}xF$QD3qGeE=?2#_0*Ac-(Y wJrd+*G)Q1dMy+`OkcTrs#25;Y4b*Hjgf;Jsk@~ literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServerConfigIF.class b/target/classes/org/productivity/java/syslog4j/server/impl/net/tcp/ssl/SSLTCPNetSyslogServerConfigIF.class new file mode 100644 index 0000000000000000000000000000000000000000..d2bc09914114213fd85fc2c741f887171717775a GIT binary patch literal 542 zcmbV}u};G<5QfjCG^Hg_D0u;grc0CZrBrT; zOU735V*SXG)mCZ2xT&~V==@cRyXDnxKmxHgf)++^$`oZKv8K)7wsG8K)HWt6-wH)@ zjug{^TC3=vwFykx=X-j|c!~rb{?Y08>kkMJ=(%;^{&LtS(1$|+7Y7hDap?KT^T_kq Q^Ree}$F9za+k0^O4LRkVy#N3J literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServer.class b/target/classes/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServer.class new file mode 100644 index 0000000000000000000000000000000000000000..6da1637e7ee4b920c2b97b453b6e8a1af3c309cc GIT binary patch literal 3674 zcmb_f`BM}}6#jZy7+3~H#0&34!@8*J9TlSyL|t5vh@hy64!h$rxXj?pEFL*b%zeiz zhe?b%s`xcjMWB+DKbori1Nm=~d_A-54haU26tz9CyWjD>_xinVe*g35y8zbXhX__8 zQGpd`mDB-AB_n7<(XmX`jPE&G7%c(Ah(-F);5+Gm;@I_XZT0@@pv=RB%=xly(Fb zB>S}?EpF;=e2?a88Cx6Zv{Gkuw^5*MhhZA-PJxo>s&0XBvz68bW+n|&Z_f?%>h@u+ zH_Mfpq?OXL-I{I4d44hM_8HW_FKOAC_@Hg2b1BytGTaMs&!BU`$y%9B{c%UPhjcq` z3=C#H6uI7$EI_1S zNv@A9ON%UB<{6W4_gjt|S8)LsRlJCoRJ<&=U%@2>uc~+rm#OqV=TXJ$ctdJ_Qx0#b*oaM1{o4Zb z3nKpryujkZ)>Hvk@ebad%A_9xY3Mx_@8bg%AL1hwA4>$E;EIZ?xTfMdK3DOD1b`yp548UYip@V zg(k3h8V&xDJCrkBV?ZyQCw2k9r2Tqrw#?H;<{`^}Dm=a-p6Q1P(ESy$eP!5L^3CFi zX0X=S-C70KPvdsZHL`Kv_b!rbWCEp5R@YfX;b^ODkmZKc>?PjQd5rtsIS^22Q&u{g z(?l1_YGx+h>Dq>wp>wr`V;bl;0u_{Ny3no-u-IZzzl?)|fsPiCqdsY{!?Jzn*a+&P ziDK&svU+_znvfqsz}0=4na=8oK&RaneS}uTE+kc!MUOXmx|Mt<5m=OWBY5HD8;+Ea z9#5Q|os88qNy%Rx!7k`adu>oEOX_CE?PKF2UFh%gC$b<>1j8Xv>E9k+FBQ1@D9#rU z(E0mB{So{scK1p@N#25j?|JSzd27k5P(V$XrfxT9HOJ98{o_ILd)Mz&WwT;J_oLiM z%tA2$6Blwm+m8_fc~E3N+vv8IVQo}< zNHz8Ow@2ZW)CEt;q&-&H%zP3io*@F~gPITa_UkG4v12ybYM=oW`mR@JRX&(KI{UfB zzO?_r%4YhcV>us;EBUfzkCXQ~sZ!Fs-Z{oN+lmk=AQBsch>1H0jc^u1gIwbmsH5aU ztR|)UoLGakoC(CKCFE(5+)|4u3YU2cO9O%;FSw43VeYQykFN`k63AI^4cJH^C9$6n z9z|)z^;@XQ)8i;36}pF7`5A?BlbAiKylAuzWmNS9RjoiZ{jQ^@4K%TVW6^_+c_3l= z1j&1Fg)$|SZ4^o0V8uNw&r{=wwEcq09)GH?9z#`f7&U>VG0aFd{77*>a7&<&Ud!1! z25mj&(NH}$)6Xr~#y<&V8O_Zj$jw}nVQ$QW3UU8watq3W?u7UcK@DeHCn6=T5o#&- zZp31vn8}RAO75U~7)o*^IWjAZU(1uRam*&#>YFeHq1W~_G~6A-oHnk7R*zyX1?M%8 zn9tvWan!Yo*y=UoSU8Nv_BEqe^c$4WFlI_}6pL$?jAH4Q@SJeyHmb-uie+S8K8zVs zZesS=64xx*4`Mu2S_(AGtc7UBI$1d{krNnOXG?9M~W}}7w z_3S4{E0!S1Otw+FgLyoJ?fjqX0J=$O)OwUu4=fx<4kvJlYnO47FU?bY@b&Vkm*yi+ z_X2(b71S>n-t8P`^Vf(S91k#A&k#omwNw+!v-F^w!Ipd_)D$7ECQ|h{jb>t#$-0qG dRvjO~EyT{pHTH2mM9iP@8{x_gqW%;We*?`x?qmP} literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServerConfig.class b/target/classes/org/productivity/java/syslog4j/server/impl/net/udp/UDPNetSyslogServerConfig.class new file mode 100644 index 0000000000000000000000000000000000000000..ea6db62529d755e6ae585f1dddde2612277a918c GIT binary patch literal 1093 zcmb`F!A}!G6vn@4w^W)!v4w)AK&!;GHDP1)hA}Zkl1e2el_ngw?YazEcAMR46Ruu8 z`+w+xn0WAP{5$+RjNeQfL@WmrF7NHW`Q|s@yf;67ef{Eirq*$e%Fm+83sqKJpu7bV4)cXv2p^{b^MW=`dR<*@Z-Vv_X2azWFXaZfn=@T z6|kD&z!k`~W#Ar;&U$Y2*6I1IGGSvPXlVeYE%H&{Z8H>6mp|d?&qKny9smmthzw+HVQ0 z)Y^vVJAr3+R3rm$*GNvnn3DXzs{+LtdklBkyLPVc#JokJR=LR^lI^ihlyZcf% zVdEy#JK9|qSuA9+jFl`_u_o~HR@x$Pa4VcidjyS$V=Nm{W}}5TA`C$C#lM$irgWmiU#Oh;WxR4b7s!r~&&_YHdaX z8tWHG{Glu&$(150t2}(}Y`Zj^(~pQyqKx$fze_YTX~zz;Ub70YJ~1b# T0w_r*X4L&k?xDxe!51Ch1syYXVzHf@J4 z(c#DZ<3B=_uo1o@De7XxI3R+MAn}73MWZps#6)9I;}4_ppV4{l+kO4uhw(?xx%ZrV z&w0*y&TV`1pLeeUXhg(`GCbhKe5`fwszZu(QmmI^gA^O3cuPK5A~Ty2&j?8L*^ zqGPKxZbUv{|$4&vwNc1LShJe^DU{578X4Xt5cpGA0bg-|_ zNDJ8ZbO^ZeyReby&+Zo}NDK~in*AL^StBFhjGGB#+U1OnvbJGSHU6fvA!0ibUfK zwIrPEjl_3E(x%)`8P)85lamz8iNcseiG-0}7ms8z63dEkGTk3crIWG2-mH1h%nk*u zUHdKp#hBo^JZw9t-yuHu-An}^7`Z0C$K0qz}-$6>G+U86^X@+m_Luj zZ%VT3C6FG0stxIMGR?MWuN+CgY@C_s_h+n;s26Dcf9x?o(^$D5StC7%S%JWR56W$g z^!6H=OjSceg8y0$#U$ z*lj-vUClvNCZGho>acohX0HYU??62UU1z^G0g`*VVxNE(uuU)|zGDw~C*TNpFTpv1 zf?0S01_*i@M9*M84WpV4VL3gEwe%b|((~9%FJK#uU>Ch;!T0BZ&A{)Tg3n;(ymN6v zPB&}ritQz6AV735ApJOQ<#F!QuGquMYNg$$oxu{exh~+YR@I}9!Byw;sE4~oY$6BO zO4TTfKP| z8)O(d%|1z5MKLCa^Vv#eHtuT$ny`$2f^3k3b)EYRIt-nTppafh3B7_+I*JM!LlvDs zEuBJ;!!^+xSVm`=)pKa0*U-*q*3+BVL~k*x=dqXGhCvt5PnU3j-a~?}B1PBmBwfc4 zy^rVU29D4NI7%O4ls?8u_MN3q@H%~pEA$y|(C7GwzQ9fT8eh_P_?EuMZTbN}(~p>> z+d`$EgigPTV){)~((hs^{UMs@PqBjjwkE2NC$NgEYU27-EawN&j22#%@v~UQHU%Zv zj#hqi0;TBW6LQLic)sKf1qt+Fh2>2lX5FxfO1>?n}5CkN=sGJ3d2Lwz=% zov>5!9g^NjjcPE`6Ox(%)p46nYuL`Q#wI7_zTJgbF9r7I$A|6AA!|5E&yU ze{14WY`4Vv$-2wCyx^rFyp|%?mLj5V2rp?6nO{o&v&YQn**FlSM_0Cg=)Lbc&l zBUqwFu~H?lPC3}7#;{YJ#BP#6iD| zRq8Z))GOGlUd0i01_|{Vo>s48QoV_3bsneH1)NhC@vgdrYwB%$L88A@@8E0o9)48s z<7f3jnTTs>zy^2dz|ArxH?fgE4Sn1yow~`TWK)3>yg{FrPdeEGDXF8X>j<{8x67Vh zy-9Dqh{kY7ut`7BJ%_ta>DtUczb9qNXQtcUrV z*!^ar(4|rtStqveI%%$NYY}&++kxj6wEU_S(M~a!#P<=VaSpvyT>ceQm8&5eQ(6tV z1T#fSmflLqGAM%ohTy+No%#;#>U(slAFxsVzM!m literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/util/Base64.class b/target/classes/org/productivity/java/syslog4j/util/Base64.class new file mode 100644 index 0000000000000000000000000000000000000000..0a7fecee5e3ae8e96a78a013f1a4f074b236434d GIT binary patch literal 17866 zcmeHudwf*Yz3*@B$Lx6}ECK@z2{1e)Z$bzJ7+xkMKp-SQhDXqvOp?h1l1xk{KoHSd zt&jRB+NxBg_zWto_yQ^v>Ny_Isi%*l)z;(j^z_i$W6^4Ddu*+(-0yGgnaKpB*WUZb zz4vpgpZxY(zx7*>{d=wNT6=imqi0SLQL#Aeram!~Nj8%lCb=$ni<>!1$EO65p7Fx*9Ad^Kdu~;l|i=|?jQ(VYmWlYK~ zvD{6Q#B57cxM_;0w8RQGO%*FGvC2);#Y!esOjcWB4Y#azi)s+`0cWk7@U*x{xovC~aq9=B2K zVlvx=XW@>F%FG`eeQ8*0~us%mTM1c@p^Y0IPCeX($NY*V4EU&Gop0V$FhNnVPer!5jI>+ER{H$`HC%$%xRp5Is=ZHZvr)g9fDn*Oe) zNN*_I)Co>Tb+kF$xhdS+!Sy)PiuS}hU{5#!MyrT4M_cUS9E&@;J7P-(={dQZFlwy5 z140GW(cZSAp5ACne{-y3M@MX+NU5@KpszF9Hg{W5f2^aks65;kDV+dfOUQBJ%wn#I2=fzjv5iP2Vz#yF+ zyV)pw&eK(2+IG2p{qt5Td*2aCav7n98n$t>&5w)qN+BPulM(( z*UaPsHg@;*_w+=2W096hRypD+RorL_M`6k-NqN?CS#NK6ATPUB6tX)ugOSC&yp3)tD%rP@J7Da!K89NG)^<626$6-r>8Gj|tJ3MO%;>r{4kMXSQ zqJ4O2N7G!pAUd$1zNU`ly;11gg_24(a3mcaI7iq9OHIlup9#Fx_z@cIP}ch+7y>TF z*=cgpGmH@QmQiABVlOKY_bzZx~+mxG!c(8 zM_6L2OW1N)!?cw5R9kLMG`1qz-`$cLGikO@wj@S(Mw_<99aN9!J$ zw>eu1(|hfaL(vr~JU2}g+QbVYBp%O1(#IpL+rcV#x-!HH}g*9OusJ8Vk@7R&2l-7NTP zf@!$o(rxVwE#ZG=)+Bt0XOZ|qWPBW~H=$_*VFm}%BfFY`6nI-q$*)6z3$G{bcjA{# zbasc8#%Ii)JsX{Ofh0J^Hm8``2ybmy2@}Mjwrk#y)Et&dbSdGAb8#~=f!g8Sb!vaJ zb?&h@?^(R9d+7*0?xp{rpKKIAgJ6Ki3fS)wD2(hWYzcI* zlG&pINI3DLm+sLNew?N=cJC$Qa1~l zm{^1zu)`$8E#k{wv5yrzMv19hnM@m&xHZu*e9QKV+qjP$>SKGYSA0c$6)A0FXhq=y zp8s}1GZOQE+NRF3cX;WC^om#9DfV;qYfMl&D{jECgAH^SOdAA#pIjbpNf<(zAkf?% z?hQA`BE5ld3<9nk_(7D-vsuwghrml@B0X15Lc~ z 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 ZF2Ij}2-krcO~HjyKQ2WZ@!UzS{{f&V^1T26 literal 0 HcmV?d00001 diff --git a/target/classes/org/productivity/java/syslog4j/util/OSDetectUtility.class b/target/classes/org/productivity/java/syslog4j/util/OSDetectUtility.class new file mode 100644 index 0000000000000000000000000000000000000000..40187b21a62021faf2a001ded0b18d2870f816c0 GIT binary patch literal 1587 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

QX;d_k_?@GWf(=L7_powEivm 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≥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 R#&__a0~5-esgN`n{|6b{6o&u+ literal 0 HcmV?d00001