camel-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From James Strachan <james.strac...@gmail.com>
Subject Re: [DISCUSS] - Camel 2.0 - Case insensitive headers on Camel Message
Date Mon, 10 Aug 2009 09:25:40 GMT
FWIW I'm liking the fact that lookups become case insensitive; as its
what folks expect in HTTP/Mail type scenarios. Using a custom Map also
makes it possible for a component/endpoint to disable this feature if
it wishes (or use a different Map implementation if it can think of a
good reason to do so).

2009/8/10 Claus Ibsen <claus.ibsen@gmail.com>:
> Hi
>
> Had a chat James as well.
>
> Went for the solution without a KeyValuePair object as it causes pain
> with dynamic languages and template engines. And the camel-jms
> component had some obscure errors with it also.
>
> Its very easy to revert to old behavior as its just to change to use a
> java.util.HashMap in DefaultMessage.
>
>
> On Sat, Aug 8, 2009 at 9:53 PM, Hadrian Zbarcea<hzbarcea@gmail.com> wrote:
>> Hi Claus,
>>
>> I added a comment on the Jira as well.
>>
>> Why not use a Map<lowercase-header, Pair<header, Object>> ?  I believe
this
>> to be a simple solution.  Lookups should always be on the lowercase version
>> of the header, on the wire the original version should go.
>>
>> What do you think?
>> Hadrian
>>
>> On Aug 8, 2009, at 9:42 AM, Claus Ibsen wrote:
>>
>>> Hi
>>>
>>> I have just attached a much better implementation of the map, this
>>> time all code is in a single class and it does not use holder objects
>>> such as a KeyValuePair when storing the value.
>>>
>>> It also works out of the box with scripting engines that can access
>>> and manipulate the headers such as Freemarker and Velocity.
>>>
>>> The changes needed in DefaultMessage is basically to use this map
>>> instead of a regular HashMap.
>>> And when its copied to another map the original keys is automatic
>>> retained.
>>>
>>>
>>>
>>> On Sat, Aug 8, 2009 at 12:42 PM, Claus Ibsen<claus.ibsen@gmail.com> wrote:
>>>>
>>>> Hi
>>>>
>>>> For background see ticket CAMEL-1886
>>>> https://issues.apache.org/activemq/browse/CAMEL-1886
>>>>
>>>> The issue is that headers is stored using keys that are case
>>>> sensitive, and that leads to a few problems and differences in Camel:
>>>>
>>>> - lookup is cumbersome as you must match case 100%
>>>> - errors in camel components that is unable to realize a header
>>>> already exists however with a different (case)
>>>> - some protocols are agnostic to header cases, such as HTTP (and all
>>>> its different transports using HTTP), Mail, and whatnot?
>>>> - camel-mail stores notoriously headers in lower keys only
>>>> - etc.
>>>>
>>>> And most importantly
>>>> - no one wants to send different values using a key that have
>>>> different case, such as:
>>>>  Foo=cheese
>>>>  FOO=cake
>>>>  foo=beer
>>>>
>>>> So James and I had a chat about it and to see if would could do
>>>> something about it.
>>>>
>>>> The real reason that I picked up this issue is the tuning experiment
>>>> with Camel 2.x
>>>> http://camel.apache.org/camel-2x-speed-optimizations.html
>>>>
>>>> Where we want to take a few short cuts and offer header lookup on the
>>>> source directly to avoid the "tiny" overhead of extracting headers
>>>> from the source
>>>> and populate the camel message. This is useful if you do message
>>>> routing that only uses headers. The camel-jms component did already
>>>> offer this but
>>>> it also had some inconsistency in this relation.
>>>>
>>>>
>>>> I have attempted a resolution in the tuning branch but discovered an
>>>> issue, that it does take some more grunt work to keep the lower case
>>>> index in sync etc.
>>>> So I wanted to try a different approach
>>>>
>>>> CaseInsenstiveMap
>>>> ===============
>>>>
>>>> I have implemented a small case insenstive map so we can store headers
>>>> in 1 map instead of keeping 2 maps in sync.
>>>> I am still amazed why such a Map does not exists directly in the JDK
>>>> itself.
>>>>
>>>> What does this offer then
>>>> - lookup is easy as you can lookup using any case
>>>>  and in the future we could also offer lookup for special keys people
>>>> spell differently such as: ContentType, content-type, content-type,
>>>> content_type and whatnot.
>>>> - put will also ensure that it replaces existing values
>>>> - and most importantly that it offers this as well when end users work
>>>> directly on the map using:
>>>>    exchange.getIn().getHeaders().put("foo", "beer")
>>>>  That will be able to replace existing keys if they are stored using:
>>>> Foo, FOO or what not
>>>>  This is not possible today and or with a 2nd map that tracks lower
>>>> case indexes
>>>>
>>>> So how to retain the original keys.
>>>>
>>>> Well I implemented that as well, so when you e.g. copy the map to
>>>> another or extract from it using keySet it exposes a Set that uses the
>>>> original key cases.
>>>> So if you have stored using
>>>>  exchange.getIn().setHeader("Foo", "cheese")
>>>>
>>>> Then the key in the ketSet is the original key = Foo.
>>>> But you can do lookup using: foo, FOO, FoO, FOo, and whatnot :)
>>>>
>>>> Using this implementation I actually find a few bugs in existing unit
>>>> tests and camel components that double add headers using different
>>>> cases.
>>>> For example camel-cxf in the new RS support.
>>>>
>>>>
>>>> I will later attach the code to the CAMEL-1886 ticket for people of
>>>> the community to take a look and review.
>>>>
>>>>
>>>> Here is a snippet from one of the test methods to give an idea
>>>>
>>>>   public void testLookupCaseAgnosticAddHeaderRemoveHeader() {
>>>>       Map<String, Object> map = new CaseInsensitiveMap();
>>>>       assertNull(map.get("foo"));
>>>>
>>>>       map.put("foo", "cheese");
>>>>
>>>>       assertEquals("cheese", map.get("foo"));
>>>>       assertEquals("cheese", map.get("Foo"));
>>>>       assertEquals("cheese", map.get("FOO"));
>>>>       assertNull(map.get("unknown"));
>>>>
>>>>       map.put("bar", "beer");
>>>>
>>>>       assertEquals("beer", map.get("bar"));
>>>>       assertEquals("beer", map.get("Bar"));
>>>>       assertEquals("beer", map.get("BAR"));
>>>>       assertNull(map.get("unknown"));
>>>>
>>>>       map.remove("bar");
>>>>       assertNull(map.get("bar"));
>>>>       assertNull(map.get("unknown"));
>>>>   }
>>>>
>>>>
>>>> And when using the Message API
>>>>
>>>>   public void testRemoveWithDifferentCase() {
>>>>       Message msg = new DefaultMessage();
>>>>       assertNull(msg.getHeader("foo"));
>>>>
>>>>       msg.setHeader("foo", "cheese");
>>>>       msg.setHeader("Foo", "bar");
>>>>
>>>>       assertEquals("bar", msg.getHeader("FOO"));
>>>>       assertEquals("bar", msg.getHeader("foo"));
>>>>       assertEquals("bar", msg.getHeader("Foo"));
>>>>
>>>>       msg.removeHeader("FOO");
>>>>
>>>>       assertEquals(null, msg.getHeader("foo"));
>>>>       assertEquals(null, msg.getHeader("Foo"));
>>>>       assertEquals(null, msg.getHeader("FOO"));
>>>>
>>>>       assertTrue(msg.getHeaders().isEmpty());
>>>>   }
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Claus Ibsen
>>>> Apache Camel Committer
>>>>
>>>> Open Source Integration: http://fusesource.com
>>>> Blog: http://davsclaus.blogspot.com/
>>>> Twitter: http://twitter.com/davsclaus
>>>>
>>>
>>>
>>>
>>> --
>>> Claus Ibsen
>>> Apache Camel Committer
>>>
>>> Open Source Integration: http://fusesource.com
>>> Blog: http://davsclaus.blogspot.com/
>>> Twitter: http://twitter.com/davsclaus
>>
>>
>
>
>
> --
> Claus Ibsen
> Apache Camel Committer
>
> Open Source Integration: http://fusesource.com
> Blog: http://davsclaus.blogspot.com/
> Twitter: http://twitter.com/davsclaus
>



-- 
James
-------
http://macstrac.blogspot.com/

Open Source Integration
http://fusesource.com/

Mime
View raw message