On Wed, Oct 20, 2010 at 4:03 PM, Johan Edstrom <seij...@gmail.com> wrote:
> Thanks,
>
> Will hunt down the core bits too.
>
> As for the message Mina does this by default, the UDP codec basically says 
> when a UDP packet is
> "complete" I'm done and in is flipped to out, it also conforms with the BSD 
> syslog spec, i.e it is 1024
> bytes long and that is it.
>
> I'll look into the Netty side and see if I can't make a similar packet codec 
> for it.
>

Ah perfect, thats nice with the spec. Can be a bit tricky to assemble
packets together to gather the data and build the message.
I assume Netty is almost the same approach. The lead on Netty was also
lead on Mina.

> /je
> On Oct 20, 2010, at 3:40 AM, Claus Ibsen wrote:
>
>> We usually add placeholders for popular data formats in the DSL.
>>
>> So you can do marshal().sysLog().
>>
>> For example even HL7 has this, so just check a bit in camel-core how
>> it can be done.
>>
>> But a nice idea to use a data format so we can use both MINA and Netty.
>>
>> But how does Mina/Netty know when the stream of data is completed, so
>> it can emit the packet?
>> eg can you use the default codecs provided by those?
>>
>>
>>
>> On Wed, Oct 20, 2010 at 4:34 AM, Johan Edstrom <seij...@gmail.com> wrote:
>>> 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
>>> 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 = new Rfc3164SyslogDataFormat();
>>>
>>>                // we setup a Syslog  listener on a random port.
>>>                from("netty:udp://127.0.0.1:" + serverPort + "?sync=false")
>>>
>>>                    .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 = getMockEndpoint("mock:syslogReceiver");
>>>        MockEndpoint mock2 = getMockEndpoint("mock:syslogReceiver2");
>>>        mock.expectedMessageCount(1);
>>>        mock2.expectedMessageCount(1);
>>>        mock2.expectedBodiesReceived(message);
>>>        DatagramSocket ds = new DatagramSocket();
>>>
>>>        DatagramPacket packet = 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 = 
>>> LogFactory.getLog(Rfc3164SyslogConverter.class);
>>>
>>>    private static enum MONTHS {
>>>        jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
>>>    }
>>>
>>>    private final static Map<String, MONTHS> MONTH_VALUE_MAP = new 
>>> HashMap<String, MONTHS>() {
>>>        {
>>>            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 = new StringBuilder();
>>>        sbr.append("<");
>>>        if (message.getFacility() == null) {
>>>            message.setFacility(SyslogFacility.USER);
>>>        }
>>>        if (message.getSeverity() == null) {
>>>            message.setSeverity(SyslogSeverity.INFO);
>>>        }
>>>        if (message.getHostname() == 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() == null) {
>>>            message.setTimestamp(new Date());
>>>        }
>>>
>>>        //SDF isn't going to help much here.
>>>
>>>        Calendar cal = GregorianCalendar.getInstance();
>>>        cal.setTime(message.getTimestamp());
>>>
>>>        String firstLetter = 
>>> MONTHS.values()[cal.get(Calendar.MONTH)].toString().substring(0, 1);  // 
>>> Get first letter
>>>        String remainder = 
>>> MONTHS.values()[cal.get(Calendar.MONTH)].toString()
>>>            .substring(1);    // Get remainder of word.
>>>        String capitalized = 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 = ByteBuffer.allocate(bytes.length);
>>>        byteBuffer.put(bytes);
>>>        byteBuffer.rewind();
>>>
>>>        SyslogMessage syslogMessage = new SyslogMessage();
>>>        Character charFound = (char) byteBuffer.get();
>>>
>>>        while (charFound != '<') {
>>>            //Ignore noise in beginning of message.
>>>            charFound = (char) byteBuffer.get();
>>>        }
>>>        char priChar = 0;
>>>        if (charFound == '<') {
>>>            int facility = 0;
>>>
>>>            while (Character.isDigit(priChar = (char) (byteBuffer.get() & 
>>> 0xff))) {
>>>                facility *= 10;
>>>                facility += Character.digit(priChar, 10);
>>>            }
>>>            syslogMessage.setFacility(SyslogFacility.values()[facility >> 
>>> 3]);
>>>            syslogMessage.setSeverity(SyslogSeverity.values()[facility & 
>>> 0x07]);
>>>        }
>>>
>>>        if (priChar != '>') {
>>>            //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 = new char[3];
>>>        for (int i = 0; i < 3; i++) {
>>>            month[i] = (char) (byteBuffer.get() & 0xff);
>>>        }
>>>        charFound = (char) byteBuffer.get();
>>>        if (charFound != ' ') {
>>>            //Invalid Message - missing mandatory space.
>>>            LOG.error("Invalid syslog message, missing a mandatory space 
>>> after month");
>>>        }
>>>        charFound = (char) (byteBuffer.get() & 0xff);
>>>
>>>        int day = 0;
>>>        if (charFound == ' ') {
>>>            //Extra space for the day - this is okay.
>>>            //Just ignored per the spec.
>>>        } else {
>>>            day *= 10;
>>>            day += Character.digit(charFound, 10);
>>>        }
>>>
>>>        while (Character.isDigit(charFound = (char) (byteBuffer.get() & 
>>> 0xff))) {
>>>            day *= 10;
>>>            day += Character.digit(charFound, 10);
>>>        }
>>>
>>>        int hour = 0;
>>>        while (Character.isDigit(charFound = (char) (byteBuffer.get() & 
>>> 0xff))) {
>>>            hour *= 10;
>>>            hour += Character.digit(charFound, 10);
>>>        }
>>>
>>>        int minute = 0;
>>>        while (Character.isDigit(charFound = (char) (byteBuffer.get() & 
>>> 0xff))) {
>>>            minute *= 10;
>>>            minute += Character.digit(charFound, 10);
>>>        }
>>>
>>>        int second = 0;
>>>        while (Character.isDigit(charFound = (char) (byteBuffer.get() & 
>>> 0xff))) {
>>>            second *= 10;
>>>            second += Character.digit(charFound, 10);
>>>        }
>>>
>>>        //The host is the char sequence until the next ' '
>>>
>>>        StringBuilder host = new StringBuilder();
>>>        while ((charFound = (char) (byteBuffer.get() & 0xff)) != ' ') {
>>>            host.append(charFound);
>>>        }
>>>
>>>        syslogMessage.setHostname(host.toString());
>>>
>>>        StringBuilder msg = new StringBuilder();
>>>        while (byteBuffer.hasRemaining()) {
>>>            charFound = (char) (byteBuffer.get() & 0xff);
>>>            msg.append(charFound);
>>>        }
>>>
>>>        Calendar calendar = 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
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>
>>
>>
>> --
>> Claus Ibsen
>> Apache Camel Committer
>>
>> Author of Camel in Action: http://www.manning.com/ibsen/
>> Open Source Integration: http://fusesource.com
>> Blog: http://davsclaus.blogspot.com/
>> Twitter: http://twitter.com/davsclaus
>
> Johan Edstrom
>
> j...@opennms.org
>
> They that can give up essential liberty to purchase a little temporary 
> safety, deserve neither liberty nor safety.
>
> Benjamin Franklin, Historical Review of Pennsylvania, 1759
>
>
>
>
>
>



-- 
Claus Ibsen
Apache Camel Committer

Author of Camel in Action: http://www.manning.com/ibsen/
Open Source Integration: http://fusesource.com
Blog: http://davsclaus.blogspot.com/
Twitter: http://twitter.com/davsclaus

Reply via email to