1   /*
2    * Copyright (c) 2003 by Atlassian Software Systems Pty. Ltd. All rights reserved.
3    */
4   package com.atlassian.spring.container;
5   
6   import com.atlassian.event.Event;
7   import org.apache.log4j.Logger;
8   import org.springframework.beans.BeansException;
9   import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
10  import org.springframework.context.ApplicationContext;
11  import org.springframework.context.ApplicationContextException;
12  import org.springframework.web.context.ContextLoader;
13  import org.springframework.web.context.support.WebApplicationContextUtils;
14  
15  import javax.servlet.ServletContext;
16  
17  /**
18   * Implementation  of ContainerContext to allow compoennts to be retrieved from a spring container
19   */
20  public class SpringContainerContext implements ContainerContext
21  {
22      private static final Logger log = Logger.getLogger(SpringContainerContext.class);
23  
24      private volatile ServletContext servletContext;
25      private volatile ApplicationContext applicationContext;
26      // @TODO Why are we inited this here like this? The only thing is maybe if Confluence needs to creteComponent before Spring is setup
27      private volatile AtlassianBeanFactory beanFactory = new AtlassianBeanFactory(null);
28  
29      public void setServletContext(ServletContext context)
30      {
31          servletContext = context;
32          setApplicationContext(WebApplicationContextUtils.getWebApplicationContext(context));
33      }
34  
35      public ServletContext getServletContext()
36      {
37          return servletContext;
38      }
39  
40      /* (non-Javadoc)
41       * @see com.atlassian.confluence.setup.container.ContainerContext#getComponent(java.lang.Object)
42       */
43      public Object getComponent(Object key) throws ComponentNotFoundException
44      {
45          if (applicationContext == null)
46          {
47              log.fatal("Spring Application context has not been set");
48              throw new IllegalStateException("Spring Application context has not been set");
49          }
50  
51          if (key == null)
52          {
53              log.error("The component key cannot be null");
54              throw new ComponentNotFoundException("The component key cannot be null");
55          }
56          if (key instanceof Class)
57          {
58              //We will assume that there should only be one object of
59              //this class in the container for now
60              String[] names = beanFactory.getBeanNamesForType((Class)key);
61              if (names == null || names.length == 0 || names.length > 1)
62              {
63                  throw new ComponentNotFoundException("The container is unable to resolve single instance of "
64                          + ((Class) key).getName()
65                          + " number of instances found was: "
66                          + names.length);
67              }
68              else
69              {
70                  key = names[0];
71              }
72          }
73          try
74          {
75              return beanFactory.getBean(key.toString());
76          }
77          catch (BeansException e)
78          {
79              throw new ComponentNotFoundException("Failed to find component: " + e.getMessage(), e);
80          }
81      }
82  
83      public Object createComponent(Class clazz)
84      {
85          return beanFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
86      }
87  
88      public Object createCompleteComponent(Class clazz)
89      {
90          return beanFactory.createBean(clazz, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
91      }
92  
93      /**
94       * autowire the dependences a bean that has already been created
95       *
96       * @param bean
97       */
98      public void autowireComponent(Object bean)
99      {
100         if (beanFactory != null)
101         {
102             beanFactory.autowireBeanProperties(bean, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
103         }
104         else
105         {
106             log.debug("ApplicationContext is null or has not been set. Cannot proceed with autowiring of component: " + bean);
107         }
108     }
109 
110     /*
111 	 * (non-Javadoc)
112 	 * 
113 	 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
114 	 */
115     public void setApplicationContext(ApplicationContext appContext)
116             throws ApplicationContextException
117     {
118         if (appContext != null)
119         {
120             applicationContext = appContext;
121             beanFactory = new AtlassianBeanFactory(appContext.getAutowireCapableBeanFactory());
122         }
123         else
124         {
125             applicationContext = null;
126             beanFactory = null;
127         }
128     }
129 
130     /*
131 	 * @see com.atlassian.confluence.setup.container.ContainerContext#refresh()
132 	 */
133     public synchronized void refresh()
134     {
135         ContextLoader loader = new ContextLoader();
136 
137         // if we have an existing spring context, ensure we close it properly
138         ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
139 
140         if (ctx != null)
141         {
142             loader.closeWebApplicationContext(servletContext);
143         }
144 
145         loader.initWebApplicationContext(servletContext);
146 
147         if (applicationContext == null)
148         {
149             setApplicationContext(WebApplicationContextUtils.getWebApplicationContext(servletContext));
150         }
151 
152         contextReloaded();
153     }
154 
155     public boolean isSetup()
156     {
157         return applicationContext != null;
158     }
159 
160     protected void contextReloaded()
161     {
162         if (applicationContext != null)
163         {
164             applicationContext.publishEvent(new ContainerContextLoadedEvent(applicationContext));
165         }
166     }
167 
168     protected ApplicationContext getApplicationContext()
169     {
170         return applicationContext;
171     }
172 
173     public void publishEvent(Event e)
174     {
175         applicationContext.publishEvent(e);
176     }
177 }