users@jms-spec.java.net

[jms-spec users] [jsr343-experts] Re: JMS 2.0 Late update: JMSProducer.getPropertyNames()

From: John D. Ament <john.d.ament_at_gmail.com>
Date: Mon, 21 Jan 2013 16:40:38 -0500

Nigel,

If it's backed by the Map's entrySet then it should definitely be
unmodifiable. The set is unmodifiable, if you make changes to the
underlying map they should be reflected in the map.


On Mon, Jan 21, 2013 at 10:29 AM, Nigel Deakin <nigel.deakin_at_oracle.com>wrote:

> John,
>
>
> On 21/01/2013 13:51, John D. Ament wrote:
>
>> Hi Nigel,
>>
>> If there are no properties set on the JMSProducer, will this return null
>> or the equivalent of Collections.EMPTY_SET ?
>>
>
> It returns an empty Set. Returning null would force the application to add
> code to handle this case.
>
>
> Since you should not modify it, can we call it an immutable set in the
>> API docs (e.g. a wrap of
>> Collections.unmodifiableSet ?)
>>
>>
> Rüdiger did suggest that and I didn't respond to it.
> Collections.unmodifiableSet returns a set backed by the underlying
> collection. But if we're going to return a "backed" set, then I don't
> particularly see any reason why it needs to be unmodifiable in this
> particular case.
>
> Although I did originally suggested that this Set be a copy, there's no
> reason in practice why it needs to be, and it might be simpler to just
> adopt the same behaviour as Map#keySet, which returns "a Set view of the
> keys contained in the map".
>
> Remember that all a JMSProducer does is to maintain a Map of property
> name/value pairs which will be copied to any message which is sent.
>
> The implementation would be trivial, given that the JMSProducer would
> probably be maintaining these properties in a Map anyway.
>
> The API doc would be:
>
> ------------------------------**------------------------------**------
> Set<String> getPropertyNames()
>
> Returns a Set view of the names of all the message properties that have
> been set on this JMSProducer.
>
>
> Note that JMS standard header fields are not considered properties and are
> not returned in this Set.
>
> The set is backed by the JMSProducer, so changes to the map are reflected
> in the set, and vice-versa. Its behaviour matches that defined in the
> java.util.Map method keySet.
>
> Returns:
>
> a Set containing the names of all the message properties that have
> been set on this JMSProducer
> Throws:
> JMSRuntimeException - if the JMS provider fails to get the property
> names due to some internal error.
> See Also:
> Map.keySet()
> ------------------------------**------------------------------**------
>
> Is this better?
>
> Nigel
>
>
>
> John
>>
>>
>>
>> On Mon, Jan 21, 2013 at 7:53 AM, Nigel Deakin <nigel.deakin_at_oracle.com<mailto:
>> nigel.deakin_at_oracle.**com <nigel.deakin_at_oracle.com>>> wrote:
>>
>> Following comments, I have now drafted this small API change. You can
>> view it at
>> http://jms-spec.java.net/2.0-_**_SNAPSHOT/apidocs/javax/jms/__**
>> JMSProducer.html#__**getPropertyNames%28%29<http://jms-spec.java.net/2.0-__SNAPSHOT/apidocs/javax/jms/__JMSProducer.html#__getPropertyNames%28%29>
>>
>> <http://jms-spec.java.net/2.0-**SNAPSHOT/apidocs/javax/jms/**
>> JMSProducer.html#**getPropertyNames%28%29<http://jms-spec.java.net/2.0-SNAPSHOT/apidocs/javax/jms/JMSProducer.html#getPropertyNames%28%29>
>> >
>>
>> getPropertyNames
>>
>> Set<String> getPropertyNames()
>>
>> Returns an Set containing the names of all the message
>> properties that have been set on this JMSProducer.
>>
>> Note that JMS standard header fields are not considered
>> properties and are not returned in this Set.
>>
>> The returned Set is a copy. Changes to the JMSProducer will not
>> be reflected in the Set, nor vice-versa.
>>
>> Returns:
>> a Set containing the names of property values
>> Throws:
>> JMSRuntimeException - if the JMS provider fails to get the
>> property names due to some internal error.
>>
>> Nigel
>>
>>
>> On 11/01/2013 16:07, Nigel Deakin wrote:
>>
>> I'd like to propose we accept Philippe's proposal and change the
>> definition of JMSProducer#getPropertyNames() to
>> return
>> a Set <String> instead of an Enumeration.
>>
>> I propose that for simplicity this be a copy of the property
>> names. It would not be backed by the underlying
>> collection,
>> unlike Map#keySet. I cannot conceive of a use case where that
>> would be needed.
>>
>> Although this is a minor change, if we are going to make it we
>> have to make it before JMS 2.0 is released, since we
>> won't be able to change it after that.
>>
>> Any comments?
>>
>> Nigel
>>
>>
>>
>> On 07/01/2013 12:40, Nigel Deakin wrote:
>>
>> Philippe - Thank you for your detailed and well-argued
>> message. I think you make a very good case for changing
>> JMSProducer#getPropertyNames
>> from
>> Enumeration getPropertyNames()
>> to
>> Set<String>
>>
>> I think that probably is a good change.
>>
>> However I think it is worth me pointing out that this method
>> (either version) will be used rarely, since all
>> it does it
>> allow an application to discover what property names were set
>> using prior calls to JMSProducer#setProperty()
>> on the same
>> JMSProducer object.
>>
>> Although JMSProducer#getPropertyNames() and the various
>> JMSProducer#get*Property methods such as
>> JMSProducer#getLongProperty() were added for completeness and
>> consistency I think there are few use cases
>> where they
>> would be used. So are they needed at all?
>>
>> Nigel
>>
>>
>> On 04/01/2013 18:57, Philippe Marschall wrote:
>>
>>
>>
>> On 04.01.2013 11:57, Nigel Deakin wrote:
>>
>> Hi Philippe,
>>
>> On 03/01/2013 22:14, Philippe Marschall wrote:
>>
>> Hi
>>
>> Why is the return type of
>> JMSProducer#getProperyNames() a raw (!)
>> Enumeration instead of a Set<String>?
>>
>>
>> Good question. This method (and many other methods on
>> JMSProducer) is
>> simply a copy of the corresponding method on Message.
>> And
>> Message#getPropertyNames returns a "raw" Enumeration.
>>
>> http://docs.oracle.com/javaee/**
>> __6/api/javax/jms/Message.**html#__getPropertyNames%28%29<http://docs.oracle.com/javaee/__6/api/javax/jms/Message.html#__getPropertyNames%28%29>
>>
>> <http://docs.oracle.com/**javaee/6/api/javax/jms/**
>> Message.html#getPropertyNames%**28%29<http://docs.oracle.com/javaee/6/api/javax/jms/Message.html#getPropertyNames%28%29>
>> >
>>
>>
>>
>> (Both methods return a collection of message property
>> names)
>>
>> Hmm. There are two issues here:
>>
>> 1. whether it should return an Enumeration or a Set
>> 2. whether it should use a generic type, i.e. <String>
>>
>> In general I think we should avoid try to keep the
>> methods on
>> JMSProducer and Message consistent since the user
>> will need to use both.
>>
>> (The exception to this is that whereas Message has
>> nine methods to set
>> properties with names like setStringProperty,
>> setShortProperty etc,
>> JMSProducer has nine methods all called setProperty.
>> So I have broken my
>> own "rule" in this case in order to simplify the API.)
>>
>>
>> My understanding is that JMSProducer is the "new, clutter
>> free, boiler
>> plate free, concise" API. Enumeration itself is a pretty
>> useless
>> interface. There are no useful methods like #contains or
>> #size, you
>> can't put it into an enhanced-for-loop and it likely
>> won't work with
>> Java 8 "functional methods". You always have to iterate
>> which is
>> inefficient or convert to a Set which is boiler plate.
>>
>> It starts with simple things, iteration with a Set you
>> can do
>>
>> for (String properytName : producer.getProperyNames()) {
>>
>> }
>>
>> with an enumeration you do
>>
>> Enumeration<?> enumeration = producer.getProperyNames();
>> while (enumeration.hasMoreElements()**__) {
>>
>> String properytName = enumeration.nextElement();
>> }
>>
>> but goes on to things like #contains, with a Set you can
>> do:
>>
>> producer.getProperyNames().__**
>> contains("JMSXProducerTXID")
>>
>>
>> but with an enumeration you write the following which is
>> probably also
>> less efficient because you do a linear scan
>>
>> boolean contains = false;
>> Enumeration<?> enumeration = producer.getProperyNames();
>> while (enumeration.hasMoreElements()**__) {
>> if ("JMSXProducerTXID".equals(__**enumeration.nextElement()))
>> {
>>
>> contains = true;
>> break;
>> }
>> }
>>
>> With Java 8 (which should ship this year) and a Set you
>> can do:
>>
>> Set<String> jmsxProperties = producer.getProperyNames().__
>> **filter(p ->
>>
>> p.startsWith("JMSX"));
>>
>> If you don't return a Set you'll have to do
>>
>> Set<String> jmsxProperties = new HashSet<>();
>> Enumeration<?> enumeration = producer.getProperyNames();
>> while (enumeration.hasMoreElements()**__) {
>>
>> String nextElement = (String) enumeration.nextElement();
>> if (nextElement.startsWith("JMSX"**__)) {
>> jmsxProperties.add(__**nextElement);
>>
>> }
>> }
>>
>>
>>
>> My feeling is that returning a generic type would be
>> a fairly
>> transparent improvement.
>>
>> However, given that Message#getPropertyNames returns
>> an Enumeration I
>> think it might be confusing if
>> JMSProducer#getPropertyNames returns a
>> Set.
>>
>>
>> Look at your current code that uses #getProperyNames and
>> look how much
>> simpler, easier to understand and less error prone it
>> would be when
>> #getProperyNames returned a Set.
>>
>> Could we at least have a second method that returns a Set?
>>
>> So I suggest we change this to return an Enumeration
>> <String>.
>>
>>
>> Cheers
>> Philippe
>>
>>
>>