View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.module.jca;
8   
9   import org.mule.MessageExchangePattern;
10  import org.mule.api.MuleContext;
11  import org.mule.api.MuleException;
12  import org.mule.api.config.ConfigurationBuilder;
13  import org.mule.api.context.MuleContextBuilder;
14  import org.mule.api.endpoint.EndpointBuilder;
15  import org.mule.api.endpoint.InboundEndpoint;
16  import org.mule.api.model.Model;
17  import org.mule.api.service.Service;
18  import org.mule.api.source.CompositeMessageSource;
19  import org.mule.config.DefaultMuleConfiguration;
20  import org.mule.config.builders.DeployableMuleXmlContextListener;
21  import org.mule.config.spring.SpringXmlConfigurationBuilder;
22  import org.mule.context.DefaultMuleContextBuilder;
23  import org.mule.context.DefaultMuleContextFactory;
24  import org.mule.endpoint.EndpointURIEndpointBuilder;
25  import org.mule.endpoint.URIBuilder;
26  import org.mule.util.ClassUtils;
27  
28  import java.io.IOException;
29  import java.io.ObjectInputStream;
30  import java.io.Serializable;
31  import java.util.HashMap;
32  import java.util.Map;
33  
34  import javax.resource.NotSupportedException;
35  import javax.resource.ResourceException;
36  import javax.resource.spi.ActivationSpec;
37  import javax.resource.spi.BootstrapContext;
38  import javax.resource.spi.ResourceAdapter;
39  import javax.resource.spi.ResourceAdapterInternalException;
40  import javax.resource.spi.endpoint.MessageEndpointFactory;
41  import javax.transaction.xa.XAResource;
42  
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  
46  /**
47   * <code>MuleResourceAdapter</code> TODO
48   */
49  public class MuleResourceAdapter implements ResourceAdapter, Serializable
50  {
51      /**
52       * Serial version
53       */
54      private static final long serialVersionUID = 5727648958127416509L;
55  
56      /**
57       * logger used by this class
58       */
59      protected transient Log logger = LogFactory.getLog(this.getClass());
60  
61      protected transient MuleContext muleContext;
62  
63      protected transient BootstrapContext bootstrapContext;
64      protected final Map<MuleEndpointKey, Service> endpoints = new HashMap<MuleEndpointKey, Service>();
65      protected String defaultJcaModelName;
66  
67      private String configurationBuilder = SpringXmlConfigurationBuilder.class.getName();
68      private String configurations;
69      private String username;
70      private String password;
71  
72      private DefaultMuleConfiguration muleConfiguration = new DefaultMuleConfiguration();
73  
74      private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException
75      {
76          ois.defaultReadObject();
77          this.logger = LogFactory.getLog(this.getClass());
78      }
79  
80      /**
81       * @see javax.resource.spi.ResourceAdapter#start(javax.resource.spi.BootstrapContext)
82       */
83      public void start(BootstrapContext bootstrapContext) throws ResourceAdapterInternalException
84      {
85          this.bootstrapContext = bootstrapContext;
86  
87          if (configurations != null)
88          {
89              ConfigurationBuilder configBuilder = null;
90              try
91              {
92                  configBuilder = (ConfigurationBuilder) ClassUtils.instanciateClass(configurationBuilder,
93                      configurations);
94              }
95              catch (Exception e)
96              {
97                  throw new ResourceAdapterInternalException(
98                      "Failed to instanciate configurationBuilder class: " + configurationBuilder, e);
99              }
100 
101             try
102             {
103                 logger.info("Initializing Mule...");
104 
105                 MuleContextBuilder contextBuilder = new DefaultMuleContextBuilder();
106                 muleConfiguration.setSystemModelType(JcaModel.JCA_MODEL_TYPE);
107                 contextBuilder.setMuleConfiguration(muleConfiguration);
108                 muleContext = new DefaultMuleContextFactory().createMuleContext(configBuilder, contextBuilder);
109                 
110                 // Make single shared application server instance of mule context
111                 // available to DeployableMuleXmlContextListener to support hot
112                 // deployment of Mule configurations in web applications.
113                 DeployableMuleXmlContextListener.setMuleContext(muleContext);
114             }
115             catch (MuleException e)
116             {
117                 logger.error(e);
118                 throw new ResourceAdapterInternalException(
119                     "Failed to load configurations: " + configurations, e);
120             }
121             try
122             {
123                 logger.info("Starting Mule...");
124                 muleContext.start();
125             }
126             catch (MuleException e)
127             {
128                 logger.error(e);
129                 throw new ResourceAdapterInternalException("Failed to start management context", e);
130             }
131         }
132     }
133 
134     /**
135      * @see javax.resource.spi.ResourceAdapter#stop()
136      */
137     public void stop()
138     {
139         logger.info("Stopping Mule...");
140         muleContext.dispose();
141         muleContext = null;
142         bootstrapContext = null;
143     }
144 
145     /**
146      * @return the bootstrap context for this adapter
147      */
148     public BootstrapContext getBootstrapContext()
149     {
150         return bootstrapContext;
151     }
152 
153     /**
154      * @see javax.resource.spi.ResourceAdapter#endpointActivation(javax.resource.spi.endpoint.MessageEndpointFactory,
155      *      javax.resource.spi.ActivationSpec)
156      */
157     public void endpointActivation(MessageEndpointFactory endpointFactory, ActivationSpec activationSpec)
158         throws ResourceException
159     {
160         if (activationSpec.getResourceAdapter() != this)
161         {
162             throw new ResourceException("ActivationSpec not initialized with this ResourceAdapter instance");
163         }
164 
165         if (activationSpec.getClass().equals(MuleActivationSpec.class))
166         {
167             MuleActivationSpec muleActivationSpec = (MuleActivationSpec) activationSpec;
168             try
169             {
170                 // Resolve modelName
171                 String modelName = resolveModelName(muleActivationSpec);
172 
173                 // Lookup/create JCA Model
174                 JcaModel model = getJcaModel(modelName);
175 
176                 // Create Endpoint
177                 InboundEndpoint endpoint = createMessageInflowEndpoint(muleActivationSpec);
178 
179                 // Create Service
180                 Service service = createJcaService(endpointFactory, model, endpoint);
181 
182                 // Keep reference to JcaService descriptor for endpointDeactivation
183                 MuleEndpointKey key = new MuleEndpointKey(endpointFactory, muleActivationSpec);
184                 endpoints.put(key, service);
185             }
186             catch (Exception e)
187             {
188                 logger.error(e.getMessage(), e);
189             }
190         }
191         else
192         {
193             throw new NotSupportedException("That type of ActicationSpec not supported: "
194                                             + activationSpec.getClass());
195         }
196 
197     }
198 
199     /**
200      * @see javax.resource.spi.ResourceAdapter#endpointDeactivation(javax.resource.spi.endpoint.MessageEndpointFactory,
201      *      javax.resource.spi.ActivationSpec)
202      */
203     public void endpointDeactivation(MessageEndpointFactory endpointFactory, ActivationSpec activationSpec)
204     {
205         if (activationSpec.getClass().equals(MuleActivationSpec.class))
206         {
207             MuleActivationSpec muleActivationSpec = (MuleActivationSpec) activationSpec;
208             MuleEndpointKey key = new MuleEndpointKey(endpointFactory, (MuleActivationSpec) activationSpec);
209             Service service = (Service) endpoints.remove(key);
210             if (service == null)
211             {
212                 logger.warn("No endpoint was registered with key: " + key);
213                 return;
214             }
215 
216             // Resolve modelName
217             String modelName = null;
218             try
219             {
220                 modelName = resolveModelName(muleActivationSpec);
221             }
222             catch (ResourceException e)
223             {
224                 logger.error(e.getMessage(), e);
225             }
226 
227             try
228             {
229                 muleContext.getRegistry().unregisterService(service.getName());
230             }
231             catch (MuleException e)
232             {
233                 logger.error(e.getMessage(), e);
234             }
235         }
236     }
237 
238     protected String resolveModelName(MuleActivationSpec activationSpec) throws ResourceException
239     {
240         // JCA specification mentions activationSpec properties inheriting
241         // resourceAdaptor properties, but this doesn't seem to work, at
242         // least with JBOSS, so do it manually.
243         String modelName = activationSpec.getModelName();
244         if (modelName == null)
245         {
246             modelName = defaultJcaModelName;
247         }
248         if (modelName == null)
249         {
250             throw new ResourceException(
251                 "The 'modelName' property has not been configured for either the MuleResourceAdaptor or MuleActicationSpec.");
252         }
253         return modelName;
254     }
255 
256     protected JcaModel getJcaModel(String modelName) throws MuleException, ResourceException
257     {
258         Model model = muleContext.getRegistry().lookupModel(modelName);
259         if (model != null)
260         {
261             if (model instanceof JcaModel)
262             {
263                 return (JcaModel) model;
264             }
265             else
266             {
267                 throw new ResourceException("Model:-" + modelName + "  is not compatible with JCA type");
268             }
269         }
270         else
271         {
272             JcaModel jcaModel = new JcaModel();
273             jcaModel.setName(modelName);
274             muleContext.getRegistry().registerModel(jcaModel);
275             return jcaModel;
276         }
277     }
278 
279     protected Service createJcaService(MessageEndpointFactory endpointFactory,
280                                        JcaModel model,
281                                        InboundEndpoint endpoint) throws MuleException
282     {
283         String name = "JcaService#" + endpointFactory.hashCode();
284         Service service = new JcaService(muleContext);
285         service.setName(name);
286         ((CompositeMessageSource) service.getMessageSource()).addSource(endpoint);
287 
288         // Set endpointFactory rather than endpoint here, so we can obtain a
289         // new endpoint instance from factory for each incoming message in
290         // JcaComponet as reccomended by JCA specification
291         service.setComponent(new JcaComponent(endpointFactory, model.getEntryPointResolverSet(), service,
292             new DelegateWorkManager(bootstrapContext.getWorkManager())));
293         service.setModel(model);
294         muleContext.getRegistry().registerService(service);
295         return service;
296     }
297 
298     protected InboundEndpoint createMessageInflowEndpoint(MuleActivationSpec muleActivationSpec)
299         throws MuleException
300     {
301         EndpointBuilder endpointBuilder = new EndpointURIEndpointBuilder(new URIBuilder(
302             muleActivationSpec.getEndpoint(), muleContext));
303 
304         endpointBuilder.setExchangePattern(MessageExchangePattern.ONE_WAY);
305 
306         return muleContext.getEndpointFactory().getInboundEndpoint(endpointBuilder);
307     }
308 
309     /**
310      * We only connect to one resource manager per ResourceAdapter instance, so any
311      * ActivationSpec will return the same XAResource.
312      * 
313      * @see javax.resource.spi.ResourceAdapter#getXAResources(javax.resource.spi.ActivationSpec[])
314      */
315     public XAResource[] getXAResources(ActivationSpec[] activationSpecs) throws ResourceException
316     {
317         return new XAResource[]{};
318     }
319 
320     /**
321      * @param password
322      */
323     public void setPassword(String password)
324     {
325         this.password = password;
326     }
327 
328     /**
329      * @param configurations
330      */
331     public void setConfigurations(String configurations)
332     {
333         this.configurations = configurations;
334     }
335 
336     /**
337      * @param userid
338      */
339     public void setUserName(String userid)
340     {
341         this.username = userid;
342     }
343 
344     public void setConfigurationBuilder(String configbuilder)
345     {
346         this.configurationBuilder = configbuilder;
347     }
348 
349     public void setModelName(String modelName)
350     {
351         this.defaultJcaModelName = modelName;
352     }
353 
354     public void setAutoWrapMessageAwareTransform(Boolean autoWrapMessageAwareTransform)
355     {
356         if (autoWrapMessageAwareTransform != null)
357         {
358             muleConfiguration.setAutoWrapMessageAwareTransform(autoWrapMessageAwareTransform);
359         }
360     }
361 
362     public void setCacheMessageAsBytes(Boolean cacheMessageAsBytes)
363     {
364         if (cacheMessageAsBytes != null)
365         {
366             muleConfiguration.setCacheMessageAsBytes(cacheMessageAsBytes);
367         }
368     }
369 
370     public void setCacheMessageOriginalPayload(Boolean cacheMessageOriginalPayload)
371     {
372         if (cacheMessageOriginalPayload != null)
373         {
374             muleConfiguration.setCacheMessageOriginalPayload(cacheMessageOriginalPayload);
375         }
376     }
377 
378     public void setClusterId(String clusterId)
379     {
380         muleConfiguration.setClusterId(clusterId);
381     }
382 
383     public void setDefaultEncoding(String encoding)
384     {
385         muleConfiguration.setDefaultEncoding(encoding);
386     }
387 
388     public void setDefaultQueueTimeout(Integer defaultQueueTimeout)
389     {
390         if (defaultQueueTimeout != null)
391         {
392             muleConfiguration.setDefaultQueueTimeout(defaultQueueTimeout);
393         }
394     }
395 
396     public void setDefaultResponseTimeout(Integer responseTimeout)
397     {
398         if (responseTimeout != null)
399         {
400             muleConfiguration.setDefaultResponseTimeout(responseTimeout);
401         }
402     }
403 
404     public void setDefaultSynchronousEndpoints(Boolean synchronous)
405     {
406         if (synchronous != null)
407         {
408             muleConfiguration.setDefaultSynchronousEndpoints(synchronous);
409         }
410     }
411 
412     public void setDefaultTransactionTimeout(Integer defaultTransactionTimeout)
413     {
414         if (defaultTransactionTimeout != null)
415         {
416             muleConfiguration.setDefaultTransactionTimeout(defaultTransactionTimeout);
417         }
418     }
419 
420     public void setDomainId(String domainId)
421     {
422         muleConfiguration.setDomainId(domainId);
423     }
424 
425     public void setServerId(String serverId)
426     {
427         muleConfiguration.setId(serverId);
428     }
429 
430     public void setShutdownTimeout(Integer shutdownTimeout)
431     {
432         if (shutdownTimeout != null)
433         {
434             muleConfiguration.setShutdownTimeout(shutdownTimeout);
435         }
436     }
437 
438     public void setWorkingDirectory(String workingDirectory)
439     {
440         muleConfiguration.setWorkingDirectory(workingDirectory);
441     }
442 
443     // Although get methods for config properties aren't really required we need to
444     // include them otherwise Geronimo does not consider them valid properties
445     
446     public String getConfigurationBuilder()
447     {
448         return configurationBuilder;
449     }
450 
451     public String getConfigurations()
452     {
453         return configurations;
454     }
455 
456     public String getUserName()
457     {
458         return username;
459     }
460 
461     public String getPassword()
462     {
463         return password;
464     }
465 
466     public String getModelName()
467     {
468         return defaultJcaModelName;
469     }
470     
471     public String getClusterId()
472     {
473         return muleConfiguration.getClusterId();
474     }
475 
476     public String getDefaultEncoding()
477     {
478         return muleConfiguration.getDefaultEncoding();
479     }
480 
481     public int getDefaultQueueTimeout()
482     {
483         return muleConfiguration.getDefaultQueueTimeout();
484     }
485 
486     public int getDefaultResponseTimeout()
487     {
488         return muleConfiguration.getDefaultResponseTimeout();
489     }
490 
491     public int getDefaultTransactionTimeout()
492     {
493         return muleConfiguration.getDefaultTransactionTimeout();
494     }
495 
496     public String getDomainId()
497     {
498         return muleConfiguration.getDomainId();
499     }
500 
501     public String getId()
502     {
503         return muleConfiguration.getId();
504     }
505 
506     public String getMuleHomeDirectory()
507     {
508         return muleConfiguration.getMuleHomeDirectory();
509     }
510 
511     public int getShutdownTimeout()
512     {
513         return muleConfiguration.getShutdownTimeout();
514     }
515 
516     public String getSystemModelType()
517     {
518         return muleConfiguration.getSystemModelType();
519     }
520 
521     public String getSystemName()
522     {
523         return muleConfiguration.getSystemName();
524     }
525 
526     public String getWorkingDirectory()
527     {
528         return muleConfiguration.getWorkingDirectory();
529     }
530 
531     public boolean isAutoWrapMessageAwareTransform()
532     {
533         return muleConfiguration.isAutoWrapMessageAwareTransform();
534     }
535 
536     public boolean isCacheMessageAsBytes()
537     {
538         return muleConfiguration.isCacheMessageAsBytes();
539     }
540 
541     public boolean isCacheMessageOriginalPayload()
542     {
543         return muleConfiguration.isCacheMessageOriginalPayload();
544     }
545 
546     public boolean isClientMode()
547     {
548         return muleConfiguration.isClientMode();
549     }
550 
551     public boolean isEnableStreaming()
552     {
553         return muleConfiguration.isEnableStreaming();
554     }
555 
556     @Override
557     public int hashCode()
558     {
559         final int prime = 31;
560         int result = 1;
561         result = prime * result + ((configurationBuilder == null) ? 0 : configurationBuilder.hashCode());
562         result = prime * result + ((configurations == null) ? 0 : configurations.hashCode());
563         result = prime * result + ((defaultJcaModelName == null) ? 0 : defaultJcaModelName.hashCode());
564         result = prime * result + ((endpoints == null) ? 0 : endpoints.hashCode());
565         result = prime * result + ((muleConfiguration == null) ? 0 : muleConfiguration.hashCode());
566         result = prime * result + ((password == null) ? 0 : password.hashCode());
567         result = prime * result + ((username == null) ? 0 : username.hashCode());
568         return result;
569     }
570 
571     @Override
572     public boolean equals(Object obj)
573     {
574         if (this == obj) return true;
575         if (obj == null) return false;
576         if (getClass() != obj.getClass()) return false;
577         MuleResourceAdapter other = (MuleResourceAdapter) obj;
578         if (configurationBuilder == null)
579         {
580             if (other.configurationBuilder != null) return false;
581         }
582         else if (!configurationBuilder.equals(other.configurationBuilder)) return false;
583         if (configurations == null)
584         {
585             if (other.configurations != null) return false;
586         }
587         else if (!configurations.equals(other.configurations)) return false;
588         if (defaultJcaModelName == null)
589         {
590             if (other.defaultJcaModelName != null) return false;
591         }
592         else if (!defaultJcaModelName.equals(other.defaultJcaModelName)) return false;
593         if (endpoints == null)
594         {
595             if (other.endpoints != null) return false;
596         }
597         else if (!endpoints.equals(other.endpoints)) return false;
598         if (muleConfiguration == null)
599         {
600             if (other.muleConfiguration != null) return false;
601         }
602         else if (!muleConfiguration.equals(other.muleConfiguration)) return false;
603         if (password == null)
604         {
605             if (other.password != null) return false;
606         }
607         else if (!password.equals(other.password)) return false;
608         if (username == null)
609         {
610             if (other.username != null) return false;
611         }
612         else if (!username.equals(other.username)) return false;
613         return true;
614     }
615 
616 }