View Javadoc
1   /**
2    * 
3    */
4   package gboat2.base.core.util;
5   
6   import gboat2.base.bridge.exception.DefaultGboatNestedException;
7   
8   import java.util.Collections;
9   import java.util.HashMap;
10  import java.util.Iterator;
11  import java.util.LinkedList;
12  import java.util.List;
13  import java.util.Map;
14  
15  import org.osgi.framework.Bundle;
16  import org.osgi.framework.BundleEvent;
17  import org.osgi.framework.BundleListener;
18  import org.slf4j.Logger;
19  import org.slf4j.LoggerFactory;
20  import org.springframework.beans.factory.NoSuchBeanDefinitionException;
21  import org.springframework.context.ApplicationContext;
22  import org.springframework.context.ApplicationContextAware;
23  import org.springframework.context.support.AbstractRefreshableApplicationContext;
24  import org.springframework.osgi.context.support.AbstractDelegatedExecutionApplicationContext;
25  import org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext;
26  
27  /**
28   * Spring的Context操作辅助类
29   * 在spring的xml中如下配置:
30   * <bean class="gboat2.base.core.util.SpringContextUtil" factory-method="getInstance"/>
31   * 
32   * @author lysming
33   */
34  // FIXME hemw  研究一下为什么将 servletContexts 由 List 改为 Map 后平台无法启动
35  public final class SpringContextUtil implements ApplicationContextAware, BundleListener {
36  
37  	private static Logger logger = LoggerFactory.getLogger(SpringContextUtil.class);
38  
39  	private static SpringContextUtil context;
40  
41  	private SpringContextUtil() {
42  	}
43  
44  	public synchronized static SpringContextUtil getInstance() {
45  		if (context == null) {
46  			context = new SpringContextUtil();
47  		}
48  		return context;
49  	}
50  
51  	private static final List<OsgiBundleXmlApplicationContext> servletContexts = Collections
52  			.synchronizedList(new LinkedList<OsgiBundleXmlApplicationContext>());
53  
54  	public final void setApplicationContext(ApplicationContext context) {
55  		synchronized (servletContexts) {
56  			logger.debug("add " + context + " to SpringContextUtil");
57  			List<OsgiBundleXmlApplicationContext> toRemoved = new LinkedList<OsgiBundleXmlApplicationContext>();
58  			if (context instanceof OsgiBundleXmlApplicationContext) {
59  				//存在同名bundle的context,删除旧的
60  				OsgiBundleXmlApplicationContext bundleContext = (OsgiBundleXmlApplicationContext) context;
61  				for (OsgiBundleXmlApplicationContext ctx : servletContexts) {
62  					if (ctx.getBundle().getSymbolicName().equals(bundleContext.getBundle().getSymbolicName())) {
63  						logger.debug(bundleContext + " is already in SpringContextUtil");
64  						toRemoved.add(ctx);
65  					}
66  				}
67  				for (OsgiBundleXmlApplicationContext ctx : toRemoved) {
68  					logger.debug("remove " + ctx);
69  					servletContexts.remove(ctx);
70  				}
71  				servletContexts.add(bundleContext);
72  			}
73  		}
74  	}
75  
76  	private OsgiBundleXmlApplicationContext getContextOfBundle(Bundle bundle) {
77  		synchronized (servletContexts) {
78  			for (OsgiBundleXmlApplicationContext context : servletContexts) {
79  				if (context.getBundle().getSymbolicName().equals(bundle.getSymbolicName())) {
80  					return context;
81  				}
82  			}
83  		}
84  
85  		return null;
86  	}
87  
88      /**
89       * 刷新 OSGI 环境中的 Spring 上下文 
90       * @param context
91       * @return 如果 context 对应的 Bundle 的状态为 ACTIVE,且成功执行 refresh() 操作,则返回 true, 反之则返回 false
92       */
93      private boolean refreshApplicationContext(AbstractDelegatedExecutionApplicationContext context) {
94          Bundle bundle = context.getBundle(); 
95          if (bundle.getState() != Bundle.ACTIVE)
96              return false;
97          
98          logger.debug("refresh Bundle [] 的 Spring ApplicationContext: {}", bundle.getSymbolicName(), context);
99          context.refresh();
100         return true;
101     }
102     
103 	/**
104 	 * 获取指定bundle内的beans
105 	 * @param className	类名称或接口名称
106 	 * @param bundle	查找的bundle
107 	 * @return 根据接口获得实现类
108 	 */
109 	public List<Object> getBeansOfType(Class<?> className, Bundle bundle) {
110 		logger.debug("try to find bean of " + className + " in " + bundle.getSymbolicName() + " ...");
111 		List<Object> beans = new LinkedList<Object>();
112 		OsgiBundleXmlApplicationContext context = getContextOfBundle(bundle);
113 		if (context != null) {
114 			Map<String, Object> map = new HashMap<String, Object>();
115 			try {
116 				@SuppressWarnings("unchecked")
117 				Map<String, Object> beansOfType = (Map<String, Object>)context.getBeansOfType(className);
118 				map = beansOfType;
119 			} catch (NoSuchBeanDefinitionException e) {
120 			} catch (IllegalStateException e) {
121 				if (context instanceof OsgiBundleXmlApplicationContext) {
122 					if (context.getBundle().getState() == Bundle.ACTIVE) {
123 						logger.debug("refresh " + context);
124 						context.refresh();
125 						try {
126 							@SuppressWarnings("unchecked")
127 							Map<String, Object> beansOfType = (Map<String, Object>)context.getBeansOfType(className);
128 							map = beansOfType;
129 						} catch (NoSuchBeanDefinitionException ignore) {
130 						}
131 					}
132 				}
133 			}
134 			if (!map.isEmpty()) {
135 				Iterator<String> it = map.keySet().iterator();
136 				String name;
137 				while (it.hasNext()) {
138 					name = it.next();
139 					beans.add(map.get(name));
140 				}
141 			}
142 		} else {
143 			throw new DefaultGboatNestedException("Can't find ApplicationContext for " + bundle.getSymbolicName());
144 		}
145 		logger.debug("find : " + beans);
146 		return beans;
147 	}
148 	
149 	public Object getBeanOfType(Class<?> className, Bundle bundle) {
150 		List<Object> objs = getBeansOfType(className, bundle);
151 		if(objs.size()==1){
152 			return objs.get(0);
153 		}else if(objs.size()>1){
154 			throw new DefaultGboatNestedException("more than one object of class["+className+"] in "+bundle.getSymbolicName());
155 		}else{
156 			return null;
157 		}
158 	}
159 
160 	public Object getBeanOfId(String id) {
161 		logger.debug("try to find bean with id " + id);
162 		synchronized (servletContexts) {
163 			Object bean;
164 			for (ApplicationContext context : servletContexts) {
165 				try {
166 					bean = context.getBean(id);
167 					if (bean != null) {
168 						logger.debug("find : " + bean);
169 						return bean;
170 					}
171 				} catch (NoSuchBeanDefinitionException e) {
172 					continue;
173 				} catch (IllegalStateException e) {
174 					if (context instanceof OsgiBundleXmlApplicationContext) {
175 						if (((OsgiBundleXmlApplicationContext) context).getBundle().getState() == Bundle.ACTIVE) {
176 							logger.debug("refresh " + context);
177 							((AbstractRefreshableApplicationContext) context).refresh();
178 							try {
179 								bean = context.getBean(id);
180 								if (bean != null) {
181 									logger.debug("find : " + bean);
182 									return bean;
183 								}
184 							} catch (NoSuchBeanDefinitionException ignore) {
185 								continue;
186 							}
187 						}
188 					}
189 				}
190 			}
191 			return null;
192 		}
193 	}
194 
195 	public Object getBeanOfId(String id, Bundle bundle) {
196 		logger.debug("try to find bean with id " + id + " in bundle[" + bundle.getSymbolicName() + "]");
197 		Object bean;
198 		OsgiBundleXmlApplicationContext context = getContextOfBundle(bundle);
199 		if (context != null) {
200 			try {
201 				bean = context.getBean(id);
202 				if (bean != null) {
203 					logger.debug("find : " + bean);
204 					return bean;
205 				}
206 			} catch (NoSuchBeanDefinitionException e) {
207 			} catch (IllegalStateException e) {
208 				if (context instanceof OsgiBundleXmlApplicationContext) {
209 					if (((OsgiBundleXmlApplicationContext) context).getBundle().getState() == Bundle.ACTIVE) {
210 						logger.debug("refresh " + context);
211 						((AbstractRefreshableApplicationContext) context).refresh();
212 						try {
213 							bean = context.getBean(id);
214 							if (bean != null) {
215 								logger.debug("find : " + bean);
216 								return bean;
217 							}
218 						} catch (NoSuchBeanDefinitionException ignore) {
219 						}
220 					}
221 				}
222 			}
223 		}
224 		return null;
225 	}
226 	
227     public <T> T getBeanOfId(String id, Bundle bundle, Class<T> requiredType) {
228         logger.debug("try to find bean with id " + id + " in bundle[" + bundle.getSymbolicName() + "]");
229         T bean = null;
230         OsgiBundleXmlApplicationContext context = getContextOfBundle(bundle);
231         if (context == null)
232             return null;
233 
234         try {
235             bean = context.getBean(id, requiredType);
236         } catch (IllegalStateException e) {
237             if (refreshApplicationContext(context)) {
238                 bean = context.getBean(id, requiredType);
239             }
240         }
241         return bean;
242     }
243     
244 	@Override
245 	public void bundleChanged(BundleEvent event) {
246 		if (event.getBundle().getState() == Bundle.RESOLVED) {
247 			OsgiBundleXmlApplicationContext bundleContext = getContextOfBundle(event.getBundle());
248 			if (bundleContext != null) {
249 				synchronized (servletContexts) {
250 					servletContexts.remove(bundleContext);
251 				}
252 			}
253 		}
254 	}
255 }