Return-Path: Delivered-To: apmail-camel-dev-archive@www.apache.org Received: (qmail 52701 invoked from network); 20 Oct 2010 02:34:40 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 20 Oct 2010 02:34:40 -0000 Received: (qmail 86259 invoked by uid 500); 20 Oct 2010 02:34:40 -0000 Delivered-To: apmail-camel-dev-archive@camel.apache.org Received: (qmail 86109 invoked by uid 500); 20 Oct 2010 02:34:39 -0000 Mailing-List: contact dev-help@camel.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@camel.apache.org Delivered-To: mailing list dev@camel.apache.org Received: (qmail 86097 invoked by uid 99); 20 Oct 2010 02:34:39 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 20 Oct 2010 02:34:39 +0000 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests=FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,SPF_PASS,T_TO_NO_BRKTS_FREEMAIL X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: domain of seijoed@gmail.com designates 209.85.213.173 as permitted sender) Received: from [209.85.213.173] (HELO mail-yx0-f173.google.com) (209.85.213.173) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 20 Oct 2010 02:34:29 +0000 Received: by yxi11 with SMTP id 11so1370025yxi.32 for ; Tue, 19 Oct 2010 19:34:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:content-type :content-transfer-encoding:subject:date:message-id:to:mime-version :x-mailer; bh=COQmUvtyifWWyq8vYMhtthjyGLiGnMSoXUYYvU8fAKM=; b=CUIetOPMlGyjnl1/x9rDND+lL2y3f+Zv91oCcjNF4z7ciSA6aHEigmo4Hd/XBZp2YM PEPC8gFnBcJ0fCq2j9wM/hWR5XoD5IkcS/VBHnjmOB3aIvYF+JWwXuSLJRuFd1iwC/N2 QnFIp1DgjR26aCFFSiwLwfVUJmcxmzbnZ/KvE= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:content-type:content-transfer-encoding:subject:date:message-id :to:mime-version:x-mailer; b=WaYWjMEaE4W/9SY1gLCkFe8RkLppf590T5uNMiWoABvpdv4ttUsDPVAhndJ789uic8 HlfvcdgSvqC/U3tcCqYRvs53RPqK3sngDCEDTby2LHquutD1YRFN0m1AjS8lCTA1lHGP YjECuTMHhPJjOoOl1nYxwK7E1dO9I127mYZOU= Received: by 10.42.164.198 with SMTP id h6mr5217657icy.41.1287542048406; Tue, 19 Oct 2010 19:34:08 -0700 (PDT) Received: from [192.168.15.8] (174-29-20-10.hlrn.qwest.net [174.29.20.10]) by mx.google.com with ESMTPS id in12sm19970872ibb.21.2010.10.19.19.34.06 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 19 Oct 2010 19:34:07 -0700 (PDT) From: Johan Edstrom Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Subject: Design advice. - Syslog DataFormat. Date: Tue, 19 Oct 2010 20:34:05 -0600 Message-Id: <7C5354FA-067A-47F7-93E3-F241FD914120@gmail.com> To: dev@camel.apache.org Mime-Version: 1.0 (Apple Message framework v1081) X-Mailer: Apple Mail (2.1081) X-Virus-Checked: Checked by ClamAV on apache.org Hey Need some design advice. I have an RFC 3164 (BSD Syslog protocol) ready DataFormat and the = necessary converters. I wanted this to work with both Netty UDP and Mina UDP after Willems = comment, and it does not have to=20 be specific whatsoever to the network library, it is just byte[] parsing = really. The test route looks like : protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { public void configure() throws Exception { context.setTracing(true); DataFormat syslogDataFormat =3D new = Rfc3164SyslogDataFormat(); // we setup a Syslog listener on a random port. from("netty:udp://127.0.0.1:" + serverPort + = "?sync=3Dfalse") .unmarshal(syslogDataFormat).process(new Processor() = { public void process(Exchange ex) { assertTrue(ex.getIn().getBody() instanceof = SyslogMessage); } }).to("mock:syslogReceiver"). = marshal(syslogDataFormat).to("mock:syslogReceiver2"); } }; And the @Test like @Test public void testSendingRawUDP() throws IOException, = InterruptedException { MockEndpoint mock =3D getMockEndpoint("mock:syslogReceiver"); MockEndpoint mock2 =3D getMockEndpoint("mock:syslogReceiver2"); mock.expectedMessageCount(1); mock2.expectedMessageCount(1); mock2.expectedBodiesReceived(message); DatagramSocket ds =3D new DatagramSocket(); DatagramPacket packet =3D new DatagramPacket(message.getBytes(), = message.getBytes().length, = InetAddress.getByName("localhost"), serverPort); ds.send(packet); mock2.assertIsSatisfied(); mock.assertIsSatisfied(); mock.reset(); mock2.reset(); } I think I also would want this to be able to handle things like = syslog-ng and the syslog protocol in the new RFC nobody implements = correctly. Right now I have this.. (this being what is below the rest of the text) I.e the question will be - what is the cleanest way of writing a = "factory like" dataformat? I'd suspect I'd get this into a bytebuffer, look for indicators, rewind, = pick parser and get a message and then on the marshal side, is there a clean way I could pick a way = that would make it into the DSL? Sorry if this sounds retarded. /je /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version = 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or = implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.camel.component.syslog; import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Map; import org.apache.camel.Converter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class Rfc3164SyslogConverter { private static final transient Log LOG =3D = LogFactory.getLog(Rfc3164SyslogConverter.class); private static enum MONTHS { jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec } private final static Map MONTH_VALUE_MAP =3D new = HashMap() { { put("jan", MONTHS.jan); put("feb", MONTHS.feb); put("mar", MONTHS.mar); put("apr", MONTHS.apr); put("may", MONTHS.may); put("jun", MONTHS.jun); put("jul", MONTHS.jul); put("aug", MONTHS.aug); put("sep", MONTHS.sep); put("oct", MONTHS.oct); put("nov", MONTHS.nov); put("dec", MONTHS.dec); } }; @Converter public static String toString(SyslogMessage message) { StringBuilder sbr =3D new StringBuilder(); sbr.append("<"); if (message.getFacility() =3D=3D null) { message.setFacility(SyslogFacility.USER); } if (message.getSeverity() =3D=3D null) { message.setSeverity(SyslogSeverity.INFO); } if (message.getHostname() =3D=3D null) { //This is massively ugly.. try { = message.setHostname(InetAddress.getLocalHost().toString()); } catch (UnknownHostException e) { message.setHostname("UNKNOWN_HOST"); } } sbr.append(message.getFacility().ordinal() * 8 + = message.getSeverity().ordinal()); sbr.append(">"); if (message.getTimestamp() =3D=3D null) { message.setTimestamp(new Date()); } //SDF isn't going to help much here. Calendar cal =3D GregorianCalendar.getInstance(); cal.setTime(message.getTimestamp()); String firstLetter =3D = MONTHS.values()[cal.get(Calendar.MONTH)].toString().substring(0, 1); // = Get first letter String remainder =3D = MONTHS.values()[cal.get(Calendar.MONTH)].toString() .substring(1); // Get remainder of word. String capitalized =3D firstLetter.toUpperCase() + = remainder.toLowerCase(); sbr.append(capitalized); sbr.append(" "); if (cal.get(Calendar.DAY_OF_MONTH) < 10) { sbr.append(" ").append(cal.get(Calendar.DAY_OF_MONTH)); } else { sbr.append(cal.get(Calendar.DAY_OF_MONTH)); } sbr.append(" "); if (cal.get(Calendar.HOUR_OF_DAY) < 10) { sbr.append("0").append(cal.get(Calendar.HOUR_OF_DAY)); } else { sbr.append(cal.get(Calendar.HOUR_OF_DAY)); } sbr.append(":"); if (cal.get(Calendar.MINUTE) < 10) { sbr.append("0").append(cal.get(Calendar.MINUTE)); } else { sbr.append(cal.get(Calendar.MINUTE)); } sbr.append(":"); if (cal.get(Calendar.SECOND) < 10) { sbr.append("0").append(cal.get(Calendar.SECOND)); } else { sbr.append(cal.get(Calendar.SECOND)); } sbr.append(" "); sbr.append(message.getHostname()); sbr.append(" "); sbr.append(message.getLogMessage()); return sbr.toString(); } @Converter public static SyslogMessage toSyslogMessage(String body) { return parseMessage(body.getBytes()); } public final static SyslogMessage parseMessage(byte[] bytes) { ByteBuffer byteBuffer =3D ByteBuffer.allocate(bytes.length); byteBuffer.put(bytes); byteBuffer.rewind(); SyslogMessage syslogMessage =3D new SyslogMessage(); Character charFound =3D (char) byteBuffer.get(); while (charFound !=3D '<') { //Ignore noise in beginning of message. charFound =3D (char) byteBuffer.get(); } char priChar =3D 0; if (charFound =3D=3D '<') { int facility =3D 0; while (Character.isDigit(priChar =3D (char) = (byteBuffer.get() & 0xff))) { facility *=3D 10; facility +=3D Character.digit(priChar, 10); } syslogMessage.setFacility(SyslogFacility.values()[facility = >> 3]); syslogMessage.setSeverity(SyslogSeverity.values()[facility & = 0x07]); } if (priChar !=3D '>') { //Invalid character - this is not a well defined syslog = message. LOG.error("Invalid syslog message, missing a > in the = Facility/Priority part"); } //Done parsing severity and facility //<169>Oct 22 10:52:01 TZ-6 scapegoat.dmz.example.org 10.1.2.3 = sched[0]: That's All Folks! //Need to parse the date. /** The TIMESTAMP field is the local time and is in the format of = "Mmm dd hh:mm:ss" (without the quote marks) where: Mmm is the English language abbreviation for the month of the year with the first character in uppercase and the other two characters in lowercase. The following are the only acceptable values: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec dd is the day of the month. If the day of the month is less than 10, then it MUST be represented as a space and then the number. For example, the 7th day of August would be represented as "Aug 7", with two spaces between the "g" and the "7". hh:mm:ss is the local time. The hour (hh) is represented in a 24-hour format. Valid entries are between 00 and 23, inclusive. The minute (mm) and second (ss) entries are between 00 and 59 inclusive. */ char[] month =3D new char[3]; for (int i =3D 0; i < 3; i++) { month[i] =3D (char) (byteBuffer.get() & 0xff); } charFound =3D (char) byteBuffer.get(); if (charFound !=3D ' ') { //Invalid Message - missing mandatory space. LOG.error("Invalid syslog message, missing a mandatory space = after month"); } charFound =3D (char) (byteBuffer.get() & 0xff); int day =3D 0; if (charFound =3D=3D ' ') { //Extra space for the day - this is okay. //Just ignored per the spec. } else { day *=3D 10; day +=3D Character.digit(charFound, 10); } while (Character.isDigit(charFound =3D (char) (byteBuffer.get() = & 0xff))) { day *=3D 10; day +=3D Character.digit(charFound, 10); } int hour =3D 0; while (Character.isDigit(charFound =3D (char) (byteBuffer.get() = & 0xff))) { hour *=3D 10; hour +=3D Character.digit(charFound, 10); } int minute =3D 0; while (Character.isDigit(charFound =3D (char) (byteBuffer.get() = & 0xff))) { minute *=3D 10; minute +=3D Character.digit(charFound, 10); } int second =3D 0; while (Character.isDigit(charFound =3D (char) (byteBuffer.get() = & 0xff))) { second *=3D 10; second +=3D Character.digit(charFound, 10); } //The host is the char sequence until the next ' ' StringBuilder host =3D new StringBuilder(); while ((charFound =3D (char) (byteBuffer.get() & 0xff)) !=3D ' = ') { host.append(charFound); } syslogMessage.setHostname(host.toString()); StringBuilder msg =3D new StringBuilder(); while (byteBuffer.hasRemaining()) { charFound =3D (char) (byteBuffer.get() & 0xff); msg.append(charFound); } Calendar calendar =3D new GregorianCalendar(); calendar.set(Calendar.MONTH, = MONTH_VALUE_MAP.get((String.valueOf(month).toLowerCase())).ordinal()); calendar.set(Calendar.DAY_OF_MONTH, day); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minute); calendar.set(Calendar.SECOND, second); syslogMessage.setTimestamp(calendar.getTime()); syslogMessage.setLogMessage(msg.toString()); if (LOG.isTraceEnabled()) { LOG.trace("Syslog message : " + syslogMessage.toString()); } return syslogMessage; } } Johan Edstrom