6

I have an ejb-jar.xml that contains configuration information for one of my MDB. In there is a configuration of:

 <activation-config-property>
        <activation-config-property-name>addressList</activation-config-property-name>
        <activation-config-property-value>mq://test.server.uk:7676</activation-config-property-value>
</activation-config-property>

As my project is built and packaged and then distributed off to users I need to be able to make sure this value can be modified as users have different server addresses.

Currently I have the option to set the address in a properties file. Is there anyway that I could modify this xml during deployment on glassfish 4.0 with the property value?

If not am I going to have to set the value every time someone wants the application and re-build it?

I am open to putting the configuration else where I just need to have it dynamic so that users can set the server addresses in a properties file.

kolossus
  • 20,559
  • 3
  • 52
  • 104
Softey
  • 1,451
  • 3
  • 21
  • 42
  • 2
    Have you thought on using a MDB annotated with `@ActivationConfigProperty` and then you could [modify the MDB class definition's annotation string parameter at runtime](http://stackoverflow.com/questions/14268981/modify-a-class-definitions-annotation-string-parameter-at-runtime)? – António Ribeiro Feb 26 '16 at 09:41
  • I'd be happy to use '@ActivationConfigProperty' if it would allow me to modify the values in the annotation. I didn't realise that was possible. – Softey Feb 27 '16 at 13:38
  • 1
    Using the `@ActivationConfigProperty` like is shown on [Example 7-3](http://docs.oracle.com/cd/E21764_01/web.1111/e15493/annotations.htm#WLMDB10008) and then using [Bill Burke's approach](http://bill.burkecentral.com/2008/01/14/scanning-java-annotations-at-runtime/) in order to scan your annotations, might solve your problem. – António Ribeiro Feb 27 '16 at 23:11
  • When I get back to my pc I will have a look. Really appreciate the links – Softey Feb 28 '16 at 10:43

2 Answers2

3

One thing you can try is to use an @AroundConstruct interceptor to set the value on the MDB at runtime. It's worthwhile to note that while it is possible to use placeholders in your ejb-jar.xml, it's primarily container-dependent, and the apparent lack of reading material on how it's done for Glassfish specifically should be a source of worry for you. Let's try this:

  1. Define an interceptor on your MDB:

    @MessageDriven
    @Interceptors(AddressListInterceptor.class)
    public class YourMDB
    
  2. Define your interceptor

    public class AddressListInterceptor {
    
        @AroundConstruct
        private void begin(InvocationContext iCtxt) {
    
            /**load your property prior to this point */
    
    
            ActivationConfigProperty addressList = new ActivationConfigProperty{
    
                                                      public String propertyName(){
                                                        return "addressList";
                                                      }
                                                      public String propertyValue(){
                                                        return theAddressList;
                                                       }
    
                                     public Class<? extends Annotation> annotationType(){
                                          return ActivationConfigProperty.class;
                                      }                 
    
                                                   };
    
              try {
                    /**get the annotations, with the intention of adding yours (addressList) to the array using the method demonstrated in 
                      http://stackoverflow.com/a/14276270/1530938  */
                   Annotations[] annotations = iCtxt.getClass().getAnnotations(); 
    
                    iCtxt.proceed(); //this will allow processing to continue as normal
               } catch (Exception ex) {
    
               } 
       }
    

Apart from the unfortunate need to scan and modify the annotations yourself, what this approach buys you is that you're allowed to step into the lifecycle of the MDB and modify the value of the annotation, just before the bean is intantiated. By the time the bean is put into service, it'll take the value you've set and everything should be in order

kolossus
  • 20,559
  • 3
  • 52
  • 104
  • Thank you for your answer. I'm not sure where your example for setting up the MDB fits into an actual MDB? Would you be able to provide a small example on injecting via annotation? – Softey Mar 02 '16 at 08:28
  • Looks like I spoke too soon. For some reason, I assumed you were writing a message producer, not a consumer. There really isn't any way other than fiddling with the annotations. See my update @Softey. P.S. It's important you confirm here that you're able to get this solution to work for you here; if it doesn't, I need to delete the answer so as not to mislead anyone else that lands on this page – kolossus Mar 02 '16 at 23:35
  • I don't get how this works @kolossus. How do you set off the interceptor from a Stateless bean (the MDB) that is only initiated once it receives a message from the producer that is connected via the addressList property? I would understand this working for a Singleton but not a stateless MDB – Softey Mar 03 '16 at 09:04
  • @Softey, `@AroundConstruct` is a lifecycle interceptor that will be triggered by the container before the MDB is even instantiated, let alone put in service. This is how this interceptor works. None of all the configuration you've set will matter until the instance of the MDB has been instantiated (like any other EJB). See [the lifecycle of an MDB](http://docs.oracle.com/cd/E13222_01/wls/docs81/ejb/message_beans.html). The container *does not* wait until a message arrives to instantiate an MDB; they're pooled like any other EJB beforehand. – kolossus Mar 03 '16 at 12:22
  • I have followed your suggestion and put it into my code but the interceptor is never initiated. I thought they were only initiated when any method in the class is invoked. I thought the highest level interceptor was a class one. – Softey Mar 03 '16 at 12:23
  • @Softey Forgot to mention that you need to declare an empty beans.xml file in your META-INF in the ear or use the [`@Priority`](http://stackoverflow.com/questions/12076586/interceptor-method-not-‌​called-with-interceptor-binding) annotation. If for some reason that doesn't still sort it out, you can configure the interceptor in your ejb-jar.xml – kolossus Mar 03 '16 at 14:54
  • Where does the @Priority annotation go? – Softey Mar 03 '16 at 15:05
  • @Softey `@Priority(Interceptor.Priority.APPLICATION)` in the interceptor; it's in the answer I linked. For the beans.xml file, [look here](http://www.cdi-spec.org/faq/) – kolossus Mar 03 '16 at 15:50
0

I found a simple way of modifying the address list in glassfish 4.0. This solution allows the rest of your @ActivationConfigProperty to still be used. For me when a user uses a setup script for the installation I can run the following commands:

asadmin server.jms-service.type = REMOTE

asadmin set configs.config.server-config.jms-service.jms-host.default_JMS_host.host=
"testserver.test.te.uk" 

asadmin restart-domain

You set the default JMS host to type REMOTE this then tells the broker to use the address defined in the default JMS host.

You then set the host address with the asadmin set command.

Once that is done you need to restart your glassfish.

This is obviously glassfish container dependant but that is all I required.

Softey
  • 1,451
  • 3
  • 21
  • 42
  • Probably should have mentioned that you didn't mind modifying your client's app server configuration. Your question was framed like you were looking for code-based solutions only – kolossus Mar 03 '16 at 17:26