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.config.spring;
8   
9   import org.mule.api.MuleContext;
10  import org.mule.api.MuleRuntimeException;
11  import org.mule.api.lifecycle.InitialisationException;
12  import org.mule.api.registry.RegistrationException;
13  import org.mule.config.i18n.MessageFactory;
14  import org.mule.lifecycle.RegistryLifecycleManager;
15  import org.mule.registry.AbstractRegistry;
16  import org.mule.util.StringUtils;
17  
18  import java.util.Collection;
19  import java.util.Collections;
20  import java.util.Map;
21  import java.util.concurrent.atomic.AtomicBoolean;
22  
23  import org.springframework.beans.FatalBeanException;
24  import org.springframework.beans.factory.NoSuchBeanDefinitionException;
25  import org.springframework.context.ApplicationContext;
26  import org.springframework.context.ConfigurableApplicationContext;
27  
28  public class SpringRegistry extends AbstractRegistry
29  {
30      public static final String REGISTRY_ID = "org.mule.Registry.Spring";
31  
32      /**
33       * Key used to lookup Spring Application Context from SpringRegistry via Mule's
34       * Registry interface.
35       */
36      public static final String SPRING_APPLICATION_CONTEXT = "springApplicationContext";
37  
38      protected ApplicationContext applicationContext;
39  
40      //This is used to track the Spring context lifecycle since there is no way to confirm the
41      //lifecycle phase from the application context
42      protected AtomicBoolean springContextInitialised = new AtomicBoolean(false);
43  
44      public SpringRegistry(MuleContext muleContext)
45      {
46          super(REGISTRY_ID, muleContext);
47      }
48  
49      public SpringRegistry(String id, MuleContext muleContext)
50      {
51          super(id, muleContext);
52      }
53  
54      public SpringRegistry(ApplicationContext applicationContext, MuleContext muleContext)
55      {
56          super(REGISTRY_ID, muleContext);
57          this.applicationContext = applicationContext;
58      }
59  
60      public SpringRegistry(String id, ApplicationContext applicationContext, MuleContext muleContext)
61      {
62          super(id, muleContext);
63          this.applicationContext = applicationContext;
64      }
65  
66      public SpringRegistry(ConfigurableApplicationContext applicationContext, ApplicationContext parentContext, MuleContext muleContext)
67      {
68          super(REGISTRY_ID, muleContext);
69          applicationContext.setParent(parentContext);
70          this.applicationContext = applicationContext;
71      }
72  
73      public SpringRegistry(String id, ConfigurableApplicationContext applicationContext, ApplicationContext parentContext, MuleContext muleContext)
74      {
75          super(id, muleContext);
76          applicationContext.setParent(parentContext);
77          this.applicationContext = applicationContext;
78      }
79  
80      @Override
81      protected void doInitialise() throws InitialisationException
82      {
83          if (applicationContext instanceof ConfigurableApplicationContext)
84          {
85              ((ConfigurableApplicationContext) applicationContext).refresh();
86          }
87          //This is used to track the Spring context lifecycle since there is no way to confirm the lifecycle phase from the application context
88          springContextInitialised.set(true);
89      }
90  
91      @Override
92      public void doDispose()
93      {
94          // check we aren't trying to close a context which has never been started,
95          // spring's appContext.isActive() isn't working for this case
96          if (!this.springContextInitialised.get())
97          {
98              return;
99          }
100 
101         if (applicationContext instanceof ConfigurableApplicationContext
102                 && ((ConfigurableApplicationContext) applicationContext).isActive())
103         {
104             ((ConfigurableApplicationContext) applicationContext).close();
105         }
106 
107         // release the circular implicit ref to MuleContext
108         applicationContext = null;
109 
110         this.springContextInitialised.set(false);
111     }
112 
113     @Override
114     protected RegistryLifecycleManager createLifecycleManager()
115     {
116         return new SpringRegistryLifecycleManager(getRegistryId(), this, muleContext);
117     }
118 
119     public Object lookupObject(String key)
120     {
121         if (StringUtils.isBlank(key))
122         {
123             logger.warn(
124                     MessageFactory.createStaticMessage("Detected a lookup attempt with an empty or null key"),
125                     new Throwable().fillInStackTrace());
126             return null;
127         }
128 
129         if (key.equals(SPRING_APPLICATION_CONTEXT) && applicationContext != null)
130         {
131             return applicationContext;
132         }
133         else
134         {
135             try
136             {
137                 return applicationContext.getBean(key);
138             }
139             catch (NoSuchBeanDefinitionException e)
140             {
141                 logger.debug(e);
142                 return null;
143             }
144         }
145     }
146 
147     public <T> Collection<T> lookupObjects(Class<T> type)
148     {
149         return lookupByType(type).values();
150     }
151     
152     /**
153      * For lifecycle we only want spring to return singleton objects from it's application context
154      */
155     @Override
156     public <T> Collection<T> lookupObjectsForLifecycle(Class<T> type)
157     {
158         return internalLookupByType(type, false, false).values();
159     }
160 
161     @SuppressWarnings("unchecked")
162     public <T> Map<String, T> lookupByType(Class<T> type)
163     {
164         return internalLookupByType(type, true, true);
165     }
166 
167     @SuppressWarnings("unchecked")
168     protected <T> Map<String, T> internalLookupByType(Class<T> type, boolean nonSingletons, boolean eagerInit)
169     {
170         try
171         {
172             return applicationContext.getBeansOfType(type, nonSingletons, eagerInit);
173         }
174         catch (FatalBeanException fbex)
175         {
176             // FBE is a result of a broken config, propagate it (see MULE-3297 for more details)
177             String message = String.format("Failed to lookup beans of type %s from the Spring registry", type);
178             throw new MuleRuntimeException(MessageFactory.createStaticMessage(message), fbex);
179         }
180         catch (Exception e)
181         {
182             logger.debug(e);
183             return Collections.emptyMap();
184         }
185     }
186     
187     
188     ////////////////////////////////////////////////////////////////////////////////////
189     // Registry is read-only
190     ////////////////////////////////////////////////////////////////////////////////////
191 
192     public void registerObject(String key, Object value) throws RegistrationException
193     {
194         throw new UnsupportedOperationException("Registry is read-only so objects cannot be registered or unregistered.");
195     }
196 
197     public void registerObject(String key, Object value, Object metadata) throws RegistrationException
198     {
199         throw new UnsupportedOperationException("Registry is read-only so objects cannot be registered or unregistered.");
200     }
201 
202     public void registerObjects(Map objects) throws RegistrationException
203     {
204         throw new UnsupportedOperationException("Registry is read-only so objects cannot be registered or unregistered.");
205     }
206 
207     public void unregisterObject(String key)
208     {
209         throw new UnsupportedOperationException("Registry is read-only so objects cannot be registered or unregistered.");
210     }
211 
212     public void unregisterObject(String key, Object metadata) throws RegistrationException
213     {
214         throw new UnsupportedOperationException("Registry is read-only so objects cannot be registered or unregistered.");
215     }
216 
217     ////////////////////////////////////////////////////////////////////////////////////
218     // Registry meta-data
219     ////////////////////////////////////////////////////////////////////////////////////
220 
221     public boolean isReadOnly()
222     {
223         return true;
224     }
225 
226     public boolean isRemote()
227     {
228         return false;
229     }
230 
231 }