# JMS: Mehrere Durable Subscriber dynamisch zur Laufzeit erzeugen - setClientID()



## Andi22 (16. Dez 2009)

Hallo,

ich kämpfe zur Zeit mit folgendem Problem: Ich möchte zur Laufzeit mehrere JMS DurableSubscriber dynamisch erzeugen, die sich mit einem (evtl. unterschiedlichen) MessageSelector beim JMS Provider für ein Topic unter zuhilfenahme genau einer TopicConnectionFactory anmelden. Die Software läuft im Glassfish 2.1. Nachfolgend die Methode, die die Subscription erzeugt:


```
public void createTopicSubscription(String subscriptionID, String messageSelector)
{
Context ctx = null;
TopicConnection topicConnection = null;
TopicSession topicSession = null;
TopicSubscriber = null;

    try
    {
    ctx = new InitialContext();
    TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup("jms/MyTopicConnectionFactory");
            
    //Create topic connection
    topicConnection = factory.createTopicConnection();

    //Create topic session
    topicSession = topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);

    //Lookup topic
    Topic topic = (Topic) ctx.lookup("jms/MyTopic");

    //Create topic subscriber with message selector
    topicSubscriber = topicSession.createDurableSubscriber(topic, subscriptionID, messageSelector, true);
    topicSubscriber.setMessageListener(this);
    }
    catch(Exception e)
    {
    e.printStackTrace();
    }
}
```

Solange ich nur immer einen anmelde funktionierts - versuche ich aber mehrere gleichzeitig anzumelden bekomme ich folgende Exception:

```
javax.jms.JMSException: createConsumer on JMSService:jmsdirect failed for connectionId:9193858493415586560
and sessionId:9193858493418027009
due to unkown JMSService server error.
        at com.sun.messaging.jms.ra.DirectSession._createAndAddConsumer(DirectSession.java:1645)
        at com.sun.messaging.jms.ra.DirectSession.createDurableSubscriber(DirectSession.java:354)
...
Caused by: com.sun.messaging.jmq.jmsservice.JMSServiceException: 
addConsumer: Add consumer failed. Connection ID: 9193858493415586560, 
session ID: 9193858493418027009
        at com.sun.messaging.jmq.jmsserver.service.imq.IMQDirectService.addConsumer(IMQDirectService.java:1320)
        at com.sun.messaging.jms.ra.DirectSession._createAndAddConsumer(DirectSession.java:1595)
        ... 81 more
Caused by: java.lang.NullPointerException
        at com.sun.messaging.jmq.jmsserver.core.Subscription.calcHashcode(Subscription.java:260)
        at com.sun.messaging.jmq.jmsserver.core.Subscription.<init>(Subscription.java:287)
...
```

Ich meine mittlerweile herausgefunden zu haben, dass es an der clientID liegt. Wenn ich eine clientID im Admincenter des Glassfish als Property der ConnectionFactory hinzufüge, funktioniert zumindest das Anmelden eines Subscribers - beim zweiten kommt wie gesagt obige Exception. Wenn ich gar keine ClientID definiere, klappt nichtmal das anmelden eines Subscribers (obige Exception). Ich denke mal, dass jeder Subscriber eine eigene, eindeutige ClientID haben muss, deswegen wollte ich die topicConnection.setClientID() Methode hernehmen um diese zur Laufzeit eindeutig zu setzen, allerdings bekomme ich da folgende Exception, die soviel bedeutet wie: Wenn deine Applikation im Glassfish Container läuft (und das muss sie bei mir) ist die Benutzung dieser Methode verboten:


```
javax.jms.JMSException: MQJMSRA_DC2001: Unsupported:setClientID():inACC=false:
connectionId=9193858493415594497
        at com.sun.messaging.jms.ra.DirectConnection._unsupported(DirectConnection.java:864)
        at com.sun.messaging.jms.ra.DirectConnection.setClientID(DirectConnection.java:386)
...
```

Eine Lösung besteht darin für jede Subscription eine eigene TopicConnectionFactory im Glassfish mit ClientID anzulegen, allerdings würde ich das ganz gerne vermeiden - ich will nur eine TopicConnectionFactory verwenden um zur Laufzeit verschiedene Subscriber erstellen zu können, ohne für jeden per Hand eine TopicConnectionFactory anlegen zu müssen. Kennt wer für mein Problem eine funktionierende Lösung? Evtl. dynamische Erzeugung von Message Driven Beans mit Parametern wie MessageSelector zur Laufzeit - geht das überhaupt?

Beim Testen ist mir hin und wieder auch folgende Exception um die Ohren geflogen - von welchem Limit wird hier gesprochen und wo kann man das setzen?

```
javax.jms.JMSException: createConsumer on JMSService:jmsdirect failed for connectionId:9193858493415586560
and sessionId:9193858493543070721 due to destination limit for number of consumers exceeded.
        at com.sun.messaging.jms.ra.DirectSession._createAndAddConsumer(DirectSession.java:1645)
        at com.sun.messaging.jms.ra.DirectSession.createDurableSubscriber(DirectSession.java:354)
...
```

Vielen Dank für eure Hilfe - bin echt am Verzweifeln!


----------



## FArt (17. Dez 2009)

Deine TopicConnectinFactory basiert vermutlich auf einer Factory, die für den Kontext, in dem sie verwendet wird ungünstig ist, ich denke sie ist nicht spec compilant.

Die Frage ist schon, was für dich "läuft im Glassfish" bedeutet. Auch dort gibt es unterschiedliche Kontexte, in den Logik ausgeführt werden kann.

Ich habe noch nicht mit Glassfish gearbeitet, frage mich aber, warum du eine eigene ConnectionFactory benötigst. Im JBoss z.B. gibt es mehrere Factories, die für die verschiedenen Kontexte taugen.


----------



## Andi22 (17. Dez 2009)

FArt hat gesagt.:


> Deine TopicConnectinFactory basiert vermutlich auf einer Factory, die für den Kontext, in dem sie verwendet wird ungünstig ist, ich denke sie ist nicht spec compilant. Ich habe noch nicht mit Glassfish gearbeitet, frage mich aber, warum du eine eigene ConnectionFactory benötigst. Im JBoss z.B. gibt es mehrere Factories, die für die verschiedenen Kontexte taugen.


Es wurde wie üblich im Admincenter von Glassfish unter JMS Ressources eine entsprechende TopicConnectionFactory hinzugefügt - ich wüsste nicht was daran falsch wäre. Ohne einer TopicConnectionFactory läuft gar nichts.



FArt hat gesagt.:


> Die Frage ist schon, was für dich "läuft im Glassfish" bedeutet. Auch dort gibt es unterschiedliche Kontexte, in den Logik ausgeführt werden kann.


Habs schon als Java Klasse, Session Bean und Message Driven Bean probiert - das Problem liegt aber wie bereits geschildert an der clientID die nicht zur Laufzeit gesetzt werden kann, da setClientID() eine JMS Exception wirft, weil der Aufruf dieser Methode innerhalb eines EJB Containers untersagt ist - wird seine Gründe haben nur würde mich mal eine Lösung für mein Problem interessieren - mittlerweile glaub ich aber, dass es für mein Problem gar keine Lösung gibt. Ein weiterer Ansatz, nämlich Message Driven Beans zur Laufzeit zu erzeugen schlug auch fehl, da Message Driven Beans nur zur Entwicklungszeit geschrieben werden können und nicht dynamisch erzeugt werden können.

Eine weitere funktionierende Lösung neben der Eröffnung vieler TopicConnectionFactories bestet darin nur einen normalen TopicSubscriber zu erstellen - also nicht durable - dann wird nämlich auch keine ClientID benötigt - ist zwar eine Einschränkung die nicht sehr schön ist, aber wenigstens funktioniert dann die dynamische Erzeugung von unterschiedlichen TopicSubscribern mit unterschiedlichen MessageSelectors.


----------

