glassfish
  1. glassfish
  2. GLASSFISH-6580

Durable subscription created when nondurable one requested.

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: v2.1
    • Fix Version/s: v2.1.1
    • Component/s: jms
    • Labels:
      None
    • Environment:

      Operating System: All
      Platform: All

    • Issuezilla Id:
      6,580

      Description

      I am trying to configure the clustered cache of EclipseLink to use JMS in
      Glassfish v2.1-b54. I created a Glassfish cluster with 2 nodes and then:

      • Added a Physical Destination in the cluster configuration through the Admin
        Console GUI.
      • Created two JMS resources, a connection factory and a topic destination, also
        through the Admin Console GUI.

      When I run my application standalone (with the various Glassfish jars), it
      connects to the cluster and creates nondurable subscriptions so it all works
      fine. However, when I run the application inside Glassfish, for some reason
      durable subscriptions are created. This causes the application to fail because
      the client ID has not been set as shown in the stacktrace below[1]. The
      EclipseLink code that creates the subscription is (and the stacktrace shows that
      too):

      this.subscriber = topicSession.createSubscriber(topic);

      The javadoc for that method says:

      "Creates a nondurable subscriber to the specified topic."

      So, why is a durable subscriber being created? I don't think it's an issue with
      the administered object because it works fine when I run the code from a
      standalone application (which looks up the same administered object).

      Another information that might be useful is that I am using
      com.sun.appserv.naming.S1ASCtxFactory as the initial context factory name.

      [1] com.sun.messaging.jms.JMSException: [ADD_CONSUMER_REPLY(15)] [C4036]: A
      broker error occurred. :[412] [B4135]: Cannot add durable consumer null. No
      ClientID was set on connection. user=guest, broker=localhost:37676(59279) at
      org.eclipse.persistence.exceptions.EntityManagerSetupException.failedWhileProcessingProperty(EntityManagerSetupException.java:178)
      at
      org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.processSessionCustomizer(EntityManagerSetupImpl.java:1222)
      at
      org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.updateServerSession(EntityManagerSetupImpl.java:1198)
      at
      org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:237)
      at
      org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.getServerSession(EntityManagerFactoryImpl.java:69)
      at
      org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:118)
      at
      org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManagerImpl(EntityManagerFactoryImpl.java:112)
      at
      org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:100)
      at
      org.springframework.orm.jpa.JpaTransactionManager.createEntityManagerForTransaction(JpaTransactionManager.java:392)
      at
      org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:320)
      ... 42 more Caused by: Exception [EclipseLink-22112] (Eclipse Persistence
      Services - 1.0.1 (Build 20080905)):
      org.eclipse.persistence.exceptions.RemoteCommandManagerException Exception
      Description: Could not create local JMS connection with Topic
      jms/topic/eclipseLink, Topic Factory jms/connFactory/eclipseLink/all, and
      Context properties

      {org.omg.CORBA.ORBInitialPort=33700, java.naming.provider.url=iiop://localhost:33700, java.naming.factory.initial=com.sun.appserv.naming.S1ASCtxFactory, java.naming.security.principal=guest, dedicated.connection=true, java.naming.security.credentials=24D77DC031B68CE91A372A5A33219416}

      Internal
      Exception: com.sun.messaging.jms.JMSException: [ADD_CONSUMER_REPLY(15)] [C4036]:
      A broker error occurred. :[412] [B4135]: Cannot add durable consumer null. No
      ClientID was set on connection. user=guest, broker=localhost:37676(59279) at
      org.eclipse.persistence.exceptions.RemoteCommandManagerException.errorCreatingLocalJMSConnection(RemoteCommandManagerException.java:177)
      at
      org.eclipse.persistence.sessions.coordination.jms.JMSTopicTransportManager.createConnection(JMSTopicTransportManager.java:105)
      at
      org.eclipse.persistence.sessions.coordination.jms.JMSTopicTransportManager.createLocalConnection(JMSTopicTransportManager.java:78)
      at
      org.eclipse.persistence.sessions.coordination.jms.JMSTopicTransportManager.createConnections(JMSTopicTransportManager.java:147)
      at
      org.eclipse.persistence.sessions.coordination.RemoteCommandManager.initialize(RemoteCommandManager.java:149)
      at
      com.likecube.jpa.eclipselink.EclipseLinkSessionCustomizer.customize(EclipseLinkSessionCustomizer.java:94)
      at
      org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.processSessionCustomizer(EntityManagerSetupImpl.java:1220)
      ... 50 more Caused by: com.sun.messaging.jms.JMSException:
      [ADD_CONSUMER_REPLY(15)] [C4036]: A broker error occurred. :[412] [B4135]:
      Cannot add durable consumer null. No ClientID was set on connection. user=guest,
      broker=localhost:37676(59279) at
      com.sun.messaging.jmq.jmsclient.ProtocolHandler.throwServerErrorException(ProtocolHandler.java:3982)
      at
      com.sun.messaging.jmq.jmsclient.ProtocolHandler.addInterest(ProtocolHandler.java:2307)
      at
      com.sun.messaging.jmq.jmsclient.WriteChannel.addInterest(WriteChannel.java:88)
      at
      com.sun.messaging.jmq.jmsclient.ConnectionImpl.addInterest(ConnectionImpl.java:1338)
      at com.sun.messaging.jmq.jmsclient.Consumer.registerInterest(Consumer.java:145)
      at
      com.sun.messaging.jmq.jmsclient.MessageConsumerImpl.addInterest(MessageConsumerImpl.java:170)
      at
      com.sun.messaging.jmq.jmsclient.MessageConsumerImpl.init(MessageConsumerImpl.java:157)
      at
      com.sun.messaging.jmq.jmsclient.MessageConsumerImpl.<init>(MessageConsumerImpl.java:115)
      at
      com.sun.messaging.jmq.jmsclient.TopicSubscriberImpl.<init>(TopicSubscriberImpl.java:104)
      at
      com.sun.messaging.jmq.jmsclient.UnifiedSessionImpl.createSubscriber(UnifiedSessionImpl.java:313)
      at
      com.sun.messaging.jmq.jmsclient.UnifiedSessionImpl.createSubscriber(UnifiedSessionImpl.java:274)
      at
      com.sun.messaging.jms.ra.SessionAdapter.createSubscriber(SessionAdapter.java:312) at
      org.eclipse.persistence.internal.sessions.coordination.jms.JMSTopicRemoteConnection.<init>(JMSTopicRemoteConnection.java:78)
      at
      org.eclipse.persistence.sessions.coordination.jms.JMSTopicTransportManager.createConnection(JMSTopicTransportManager.java:101)
      ... 55 more

        Activity

        Hide
        cmathrusse added a comment -

        Thanks for the code example. This would work well if I were to use Spring for as
        the MmessageListener, but unfortunately I would need to make code changes to
        EclipseLink to support the use of this as well as setting the ClientID,
        something I would like to avoid. For now, I guess the only solution that I have
        is to by-pass the container all together when it comes to the ConnectionFactory
        to the JMS Server. I'll need to go directly to the Remote JMS server.

        This too is very dirty. EclipseLink wants to acquire a ConnectionFactory and
        Topic from JNDI by performing a lookup from the InitialContext. So now I am
        forced into implementing a class that mimics the functionality that I
        EclipseLink needs to perform a lookup of these two objects, which will be stored
        in the Spring Container, to simply work around an issue in GlassFish that should
        have been addressed a while back.

        Show
        cmathrusse added a comment - Thanks for the code example. This would work well if I were to use Spring for as the MmessageListener, but unfortunately I would need to make code changes to EclipseLink to support the use of this as well as setting the ClientID, something I would like to avoid. For now, I guess the only solution that I have is to by-pass the container all together when it comes to the ConnectionFactory to the JMS Server. I'll need to go directly to the Remote JMS server. This too is very dirty. EclipseLink wants to acquire a ConnectionFactory and Topic from JNDI by performing a lookup from the InitialContext. So now I am forced into implementing a class that mimics the functionality that I EclipseLink needs to perform a lookup of these two objects, which will be stored in the Spring Container, to simply work around an issue in GlassFish that should have been addressed a while back.
        Hide
        lindaschneider added a comment -

        Please forgive the fact that I know absolutely nothing about how EclipseLink
        works but ...

        If EclipseLink is retrieving the JMS connection factory object from LDAP (and
        not creating in manually) ...

        Can't you just edit the specific connection factory to set a clientID ???

        you would use imqobjmgr to point to the right object

        If that doesn't work ... you might even be able to override it on the command
        line when you start the app server e.g. pass in
        -DimqConfiguredClientID=MyID

        [Note: I can't be sure because I've never tried that specific property]

        ------------------------------------

        Also ... I may be dense (I am very JMS spec focused) but I'm really not
        understanding why any of this is an issue that can not be worked around???

        Yes - in this clustering case clientID needs to be set for Topics (and long term
        this needs to be able to be turned off - although this is different/fixed in
        v3). This isn't something that will be backported to v2.X.

        However with the current situation:

        • Setting clientID has no impact on non-durable subscribers outside of a
          glassfish cluster (where it is required)
        • There are amazing number of ways to set the clientID
          1. If using objects stored in JNDI, you can set it on that object using imqobjmgr
          2. If using objects stored in the Application server, you can set it in the
          activation specification or in the individual administered objects
          3. If you are writing code, you can use setClientID(string name) on the
          connection to set it
          4. I think you can pass it in on the command line when you start the process.

        What is the case you are running into where none of these work, and why not ??

        Can you specify how in your mind it "should work" ??

        Show
        lindaschneider added a comment - Please forgive the fact that I know absolutely nothing about how EclipseLink works but ... If EclipseLink is retrieving the JMS connection factory object from LDAP (and not creating in manually) ... Can't you just edit the specific connection factory to set a clientID ??? you would use imqobjmgr to point to the right object If that doesn't work ... you might even be able to override it on the command line when you start the app server e.g. pass in -DimqConfiguredClientID=MyID [Note: I can't be sure because I've never tried that specific property] ------------------------------------ Also ... I may be dense (I am very JMS spec focused) but I'm really not understanding why any of this is an issue that can not be worked around??? Yes - in this clustering case clientID needs to be set for Topics (and long term this needs to be able to be turned off - although this is different/fixed in v3). This isn't something that will be backported to v2.X. However with the current situation: Setting clientID has no impact on non-durable subscribers outside of a glassfish cluster (where it is required) There are amazing number of ways to set the clientID 1. If using objects stored in JNDI, you can set it on that object using imqobjmgr 2. If using objects stored in the Application server, you can set it in the activation specification or in the individual administered objects 3. If you are writing code, you can use setClientID(string name) on the connection to set it 4. I think you can pass it in on the command line when you start the process. What is the case you are running into where none of these work, and why not ?? Can you specify how in your mind it "should work" ??
        Hide
        cmathrusse added a comment -

        I'm sorry if I am missing something here pertaining to the configuration of the
        ConnectionFactory (Managed Object) in the GlassFish container but none of these
        options seems to work as needed. Let me try and address them.

        EclipseLink is designed to allow us to utilize JMS for Cache Coordination. It
        does this in a standard way by allowing us to specify the properties that are
        used to acquire an InitiaContext. We also specify the JNDI path to the
        TopicConnectionFactory and the Topic itself.

        Example:

        public void customize(Session session) throws Exception {
        RemoteCommandManager rcm = new RemoteCommandManager((CommandProcessor) session);
        java.util.Properties props = new java.util.Properties();
        props.put(Context.PROVIDER_URL, getProviderURL());
        props.put(Context.INITIAL_CONTEXT_FACTORY, getInitialContextFactory());

        JMSTopicTransportManager tm = new JMSTopicTransportManager(rcm);
        tm.setLocalContextProperties(props);
        tm.setRemoteContextProperties(props);
        tm.setTopicName(getJmsTopicName());
        tm.setTopicConnectionFactoryName(getJmsConnectionFactoryName());
        tm.setUserName(getUserName());
        tm.setPassword(getPassword());
        ....

        EclipseLink allows us to specify the local and remote contexts. Local is for
        creating a subscriber and remote is for creating a publisher. (Usually both
        Local and Remote would be the same.) This is due to EclipseLink publishing
        entity changed to the topic. The subscriber receives those changes to apply to
        entities within the cache or to invalidate those entities. Both Local and Remote
        are treated separately, so each will have a reference to a separate connection.

        Now, if I were to set the ClientID on the ConnectionFactory that is managed in
        JNDI by GlassFish, the ClientID is set on all connections created. The problem
        with this is that it only works correctly for the first connection. The second
        connection created will throw an exception because the ClientID is already in
        use. (I know for a fact because I tried it)

        So it makes sense that the ClientID must be generated and unique. Seems to me I
        could set it easily after creating the connection. Something like:

        TopicConnection topicConnection=connectionFactory.createTopicConnection();
        topicConnection.setClientID(getClientID());
        ...

        But this too fails due to a little piece of code in GlassFish that prevents the
        ClientID from being set outside of the Application Container:

        Referring to com.sun.messaging.jms.ra.ConnectionAdapter :

        public void setClientID(String clientId) throws JMSException {
        _loggerJC.entering(_className, "setClientID()", clientId);
        //System.out.println("MQRA:CA:setClientID-to-"+clientId);
        if (!inACC)

        { throw new com.sun.messaging.jms.JMSException( "MQRA:CA:Unsupported-setClientID()"); }

        checkClosed();
        xac.setClientID(clientId);
        }

        The above code prevents me from setting the ClientID from within my application
        code. (Again, I've tried..) When I call setClientID(...) I get the JMSException
        listed above.

        So if you know of a way that I can set the ClientID on the Connection or
        ConnectionFactory that will by-pass all of the Exceptions that I am receiving
        then please share it with me. At this point I'm having to by-pass the managed
        objects completely due to the Exceptions that are preventing me from using them.

        Keep in mind, none of this would be an issue if GlassFish wasn't raising the
        exception when sharing the Non-Durable Connection in the clustered environment.

        Thanks for the help...

        Show
        cmathrusse added a comment - I'm sorry if I am missing something here pertaining to the configuration of the ConnectionFactory (Managed Object) in the GlassFish container but none of these options seems to work as needed. Let me try and address them. EclipseLink is designed to allow us to utilize JMS for Cache Coordination. It does this in a standard way by allowing us to specify the properties that are used to acquire an InitiaContext. We also specify the JNDI path to the TopicConnectionFactory and the Topic itself. Example: public void customize(Session session) throws Exception { RemoteCommandManager rcm = new RemoteCommandManager((CommandProcessor) session); java.util.Properties props = new java.util.Properties(); props.put(Context.PROVIDER_URL, getProviderURL()); props.put(Context.INITIAL_CONTEXT_FACTORY, getInitialContextFactory()); JMSTopicTransportManager tm = new JMSTopicTransportManager(rcm); tm.setLocalContextProperties(props); tm.setRemoteContextProperties(props); tm.setTopicName(getJmsTopicName()); tm.setTopicConnectionFactoryName(getJmsConnectionFactoryName()); tm.setUserName(getUserName()); tm.setPassword(getPassword()); .... EclipseLink allows us to specify the local and remote contexts. Local is for creating a subscriber and remote is for creating a publisher. (Usually both Local and Remote would be the same.) This is due to EclipseLink publishing entity changed to the topic. The subscriber receives those changes to apply to entities within the cache or to invalidate those entities. Both Local and Remote are treated separately, so each will have a reference to a separate connection. Now, if I were to set the ClientID on the ConnectionFactory that is managed in JNDI by GlassFish, the ClientID is set on all connections created. The problem with this is that it only works correctly for the first connection. The second connection created will throw an exception because the ClientID is already in use. (I know for a fact because I tried it) So it makes sense that the ClientID must be generated and unique. Seems to me I could set it easily after creating the connection. Something like: TopicConnection topicConnection=connectionFactory.createTopicConnection(); topicConnection.setClientID(getClientID()); ... But this too fails due to a little piece of code in GlassFish that prevents the ClientID from being set outside of the Application Container: Referring to com.sun.messaging.jms.ra.ConnectionAdapter : public void setClientID(String clientId) throws JMSException { _loggerJC.entering(_className, "setClientID()", clientId); //System.out.println("MQRA:CA:setClientID-to-"+clientId); if (!inACC) { throw new com.sun.messaging.jms.JMSException( "MQRA:CA:Unsupported-setClientID()"); } checkClosed(); xac.setClientID(clientId); } The above code prevents me from setting the ClientID from within my application code. (Again, I've tried..) When I call setClientID(...) I get the JMSException listed above. So if you know of a way that I can set the ClientID on the Connection or ConnectionFactory that will by-pass all of the Exceptions that I am receiving then please share it with me. At this point I'm having to by-pass the managed objects completely due to the Exceptions that are preventing me from using them. Keep in mind, none of this would be an issue if GlassFish wasn't raising the exception when sharing the Non-Durable Connection in the clustered environment. Thanks for the help...
        Hide
        kumara added a comment -

        Changing version from 9.1.1 to v2.1 to reflect new name/version.

        Show
        kumara added a comment - Changing version from 9.1.1 to v2.1 to reflect new name/version.
        Hide
        Nigel Deakin added a comment -

        The problems reported in this issue occur when trying to use a non-durable topic
        subscription in a Glassfish cluster. The MQ resource adapter (JMSRA) expects
        ClientID to be set so that it can share the same subscription amongst all
        instances of Glassfish, and by the laws of JavaEE you can't explicitly set
        ClientID outside the application client container. Users are therefore running
        into "ClientID not set" errors, which are getting misreported as "Cannot add
        durable consumer, clientID not set".

        In MQ 4.4 (e.g. in Glassfish 2.1.1) you can disable the sharing of non-durable
        topic subscriptions by setting the property
        useSharedSubscriptionInClusteredContainer=false on the ManagedConnectionFactory
        (which is what you're really dealing with when you configure a MQ connection
        factory in Glassfish). You can set this in the Glassfish admin console.

        If you set this property to false, then you should no longer get "ClientID not
        set" errors (which are being misreported as "Cannot create durable subscription".

        This property is documented in the MQ 4.4 admin guide here:
        http://docs.sun.com/app/docs/doc/821-0027/aeoon?l=en&a=view

        Show
        Nigel Deakin added a comment - The problems reported in this issue occur when trying to use a non-durable topic subscription in a Glassfish cluster. The MQ resource adapter (JMSRA) expects ClientID to be set so that it can share the same subscription amongst all instances of Glassfish, and by the laws of JavaEE you can't explicitly set ClientID outside the application client container. Users are therefore running into "ClientID not set" errors, which are getting misreported as "Cannot add durable consumer, clientID not set". In MQ 4.4 (e.g. in Glassfish 2.1.1) you can disable the sharing of non-durable topic subscriptions by setting the property useSharedSubscriptionInClusteredContainer=false on the ManagedConnectionFactory (which is what you're really dealing with when you configure a MQ connection factory in Glassfish). You can set this in the Glassfish admin console. If you set this property to false, then you should no longer get "ClientID not set" errors (which are being misreported as "Cannot create durable subscription". This property is documented in the MQ 4.4 admin guide here: http://docs.sun.com/app/docs/doc/821-0027/aeoon?l=en&a=view

          People

          • Assignee:
            Satish Kumar
            Reporter:
            ijuma
          • Votes:
            3 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: