1
2
3
4
5 package gboat2.base.dao;
6
7 import gboat2.base.core.dao.IBaseDAO;
8 import gboat2.base.dao.aspect.GboatSessionFactoryAspect;
9 import gboat2.base.dao.util.GBoatDaoClassLoader;
10
11 import java.io.FileInputStream;
12 import java.io.IOException;
13 import java.net.URL;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import java.util.Set;
21 import java.util.zip.ZipEntry;
22 import java.util.zip.ZipInputStream;
23
24 import javax.persistence.Entity;
25
26 import org.apache.commons.collections.CollectionUtils;
27 import org.apache.commons.collections.MapUtils;
28 import org.apache.commons.io.IOUtils;
29 import org.apache.commons.lang3.StringUtils;
30 import org.hibernate.SessionFactory;
31 import org.osgi.framework.Bundle;
32 import org.osgi.framework.BundleActivator;
33 import org.osgi.framework.BundleContext;
34 import org.osgi.framework.BundleEvent;
35 import org.osgi.framework.BundleException;
36 import org.osgi.framework.BundleListener;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
40 import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
41 import org.springframework.context.ApplicationContext;
42 import org.springframework.context.ApplicationContextAware;
43 import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
44
45
46
47
48
49
50 public class Activator implements BundleActivator, BundleListener, ApplicationContextAware {
51
52 private static final Logger logger = LoggerFactory.getLogger(Activator.class);
53
54 private static final String MODEL_PACKAGE_HEADER = "DynamicImport-Model";
55
56
57 private static final List<Bundle> bundlesToRegistPo = new ArrayList<Bundle>();
58
59
60 private static Map<String, Bundle> bundlesCache = new HashMap<String, Bundle>();
61
62 private static Collection<AnnotationSessionFactoryBean> sessionFactoryBeans;
63 private GboatSessionFactoryAspect sessionFactoryAspect;
64
65
66 private static Map<String, List<Class<?>>> annotatedClassesMap = new HashMap<String, List<Class<?>>>();
67
68
69 private static List<Class<?>> registClasses = new ArrayList<Class<?>>();
70
71 private static GBoatDaoClassLoader gboatLoader = null;
72
73 private IBaseDAO baseDAO;
74
75 @Override
76 public void setApplicationContext(ApplicationContext applicationContext) {
77 if (sessionFactoryBeans == null) {
78 Map<String, AnnotationSessionFactoryBean> sessionFactoryBeanMap = applicationContext.getBeansOfType(AnnotationSessionFactoryBean.class);
79 if(MapUtils.isEmpty(sessionFactoryBeanMap))
80 throw new NoSuchBeanDefinitionException(AnnotationSessionFactoryBean.class, "无法将 Bundle 中的 POJO 注册到 Hibernate SessionFactory。");
81 sessionFactoryBeans = sessionFactoryBeanMap.values();
82
83 Map<String, GboatSessionFactoryAspect> sessionFactoryAspectMap = applicationContext.getBeansOfType(GboatSessionFactoryAspect.class);
84 if(MapUtils.isNotEmpty(sessionFactoryAspectMap)) {
85 if(sessionFactoryAspectMap.size() > 1)
86 throw new NoUniqueBeanDefinitionException(GboatSessionFactoryAspect.class, sessionFactoryAspectMap.keySet());
87
88 sessionFactoryAspect = sessionFactoryAspectMap.values().iterator().next();
89 }
90
91 if (bundlesToRegistPo.size() > 0) {
92 logger.debug("call registerPOJO by setApplicationContext");
93 registerPOJO();
94 }
95 }
96 }
97
98 @Override
99 public void start(BundleContext context) throws Exception {
100
101 if (gboatLoader == null) {
102
103 gboatLoader = GBoatDaoClassLoader.createBundleClassLoaderFor(context.getBundle(0), this.getClass().getClassLoader());
104 if (gboatLoader == null) {
105 System.err.println("Error while start dao bundle, init ClassLoader failed. System will exit.");
106 System.exit(0);
107 }
108 }
109
110 Bundle[] bundles = context.getBundles();
111 StringBuffer symbolicNames = new StringBuffer();
112 for (Bundle bundle : bundles) {
113 if (bundle.getState() == Bundle.ACTIVE) {
114 if (!StringUtils.isEmpty(bundle.getHeaders().get(MODEL_PACKAGE_HEADER))) {
115 symbolicNames.append("\r\n ").append(bundle.getSymbolicName());
116 bundlesToRegistPo.add(bundle);
117 }
118 }
119 }
120 logger.info("the pojo bundles is already started:{}" , symbolicNames);
121
122
123 if (CollectionUtils.isNotEmpty(bundlesToRegistPo) && CollectionUtils.isNotEmpty(sessionFactoryBeans)) {
124 logger.debug("call registerPOJO by start");
125 registerPOJO();
126 }
127
128
129 logger.info("register bundle listener for monitor PO.");
130 context.addBundleListener(this);
131 }
132
133 @Override
134 public void bundleChanged(BundleEvent event) {
135 Bundle bundle = event.getBundle();
136 synchronized (bundlesToRegistPo) {
137 if ((event.getType() & BundleEvent.STARTED) != 0) {
138
139 logger.info("STARTED => {}({})", bundle, bundle.getLastModified());
140 if (bundlesCache.containsKey(bundle.getSymbolicName())) {
141
142 Bundle oldBundle = bundlesCache.get(bundle.getSymbolicName());
143 logger.info("cached old version is : bundleId={}, state={}", oldBundle.getBundleId(), oldBundle.getState());
144 if (oldBundle.getBundleId() != bundle.getBundleId()) {
145 try {
146 oldBundle.uninstall();
147 } catch (BundleException e) {
148 logger.warn("error to uninstall old version bundle", e);
149 } catch (IllegalStateException e) {
150 logger.warn(e.getMessage());
151 }
152 }
153 bundlesCache.remove(bundle.getSymbolicName());
154 }
155
156 if (!StringUtils.isEmpty((String) bundle.getHeaders().get(MODEL_PACKAGE_HEADER))) {
157 bundlesToRegistPo.add(bundle);
158 }
159
160
161 if (CollectionUtils.isNotEmpty(bundlesToRegistPo) && CollectionUtils.isNotEmpty(sessionFactoryBeans)) {
162 logger.debug("call registerPOJO by bundleChanged");
163 registerPOJO();
164 }
165 } else if ((event.getType() & BundleEvent.STOPPED) != 0) {
166 logger.info("STOPED => {}({})", bundle, bundle.getLastModified());
167 bundlesToRegistPo.remove(bundle);
168 }
169 }
170 }
171
172
173
174
175 private synchronized void registerPOJO() {
176 while (bundlesToRegistPo.size() > 0) {
177 parseBundleClasses();
178 }
179
180 try {
181 if (annotatedClassesMap.size() > 0) {
182
183 logger.info("rebuild session factory");
184
185 if(sessionFactoryAspect == null) {
186 if(sessionFactoryBeans.size() > 1)
187 throw new NoUniqueBeanDefinitionException(AnnotationSessionFactoryBean.class, sessionFactoryBeans.size(), "没有配置 "
188 + GboatSessionFactoryAspect.class + " 切面,无法确定 POJO 与 SessionFactory 之间的对应关系,因而不支持多个 SessionFactory。");
189
190
191
192 AnnotationSessionFactoryBean bean = sessionFactoryBeans.iterator().next();
193 bean.destroy();
194 bean.setBeanClassLoader(gboatLoader);
195 bean.setAnnotatedClasses(registClasses.toArray(new Class[0]));
196 bean.afterPropertiesSet();
197 baseDAO.setDefaultSessionFactory(bean.getObject());
198 } else {
199
200 Map<SessionFactory, List<Class<?>>> sessionFactoryPojoMap = new HashMap<SessionFactory, List<Class<?>>>();
201
202 Set<Entry<String, SessionFactory>> entrySet = sessionFactoryAspect.getTargetSessionFactorys().entrySet();
203 SessionFactory defaultSessionFactory = this.baseDAO.getDefaultSessionFactory();
204 SessionFactory matchSessionFactory = null;
205 List<Class<?>> tempList;
206 for(Class<?> clazz : registClasses) {
207 matchSessionFactory = null;
208 for (Entry<String, SessionFactory> entry : entrySet) {
209 if(clazz.getName().matches(entry.getKey())) {
210 matchSessionFactory = entry.getValue();
211 break;
212 }
213 }
214
215 if(matchSessionFactory == null) {
216 matchSessionFactory = defaultSessionFactory;
217 }
218
219 tempList = sessionFactoryPojoMap.get(matchSessionFactory);
220 if(tempList == null){
221 tempList = new ArrayList<Class<?>>();
222 sessionFactoryPojoMap.put(matchSessionFactory, tempList);
223 }
224 tempList.add(clazz);
225 }
226
227
228 SessionFactory oldSessionFactory = null;
229 SessionFactory newSessionFactory = null;
230 boolean isDefault = false;
231 for(AnnotationSessionFactoryBean bean : sessionFactoryBeans) {
232 oldSessionFactory = bean.getObject();
233 isDefault = oldSessionFactory.equals(baseDAO.getDefaultSessionFactory());
234 List<Class<?>> pojoList = sessionFactoryPojoMap.get(oldSessionFactory);
235 if(CollectionUtils.isNotEmpty(pojoList)){
236 bean.destroy();
237 bean.setBeanClassLoader(gboatLoader);
238 bean.setAnnotatedClasses(pojoList.toArray(new Class[0]));
239 bean.afterPropertiesSet();
240
241
242 newSessionFactory = bean.getObject();
243 baseDAO.addSessionFactory(newSessionFactory);
244 if (isDefault) {
245
246 baseDAO.setDefaultSessionFactory(newSessionFactory);
247 }
248
249
250 for (Entry<String, SessionFactory> entry : entrySet) {
251 if(oldSessionFactory.equals(entry.getValue())) {
252 entry.setValue(newSessionFactory);
253 }
254 }
255 }
256 }
257 }
258
259 }
260 } catch (Exception e) {
261 logger.trace("Gboat2 DAO Bundle 注册 POJO 失败。", e);
262 }
263 }
264
265 private void parseBundleClasses() {
266 String[] importItems;
267 List<String> importClassNames;
268
269 synchronized (bundlesToRegistPo) {
270 List<Class<?>> importClasses = null;
271 String importPath;
272 for (Bundle bundle : bundlesToRegistPo) {
273 if (bundle == null)
274 continue;
275
276 logger.debug("register po for {}", bundle.getSymbolicName());
277 importClasses = new ArrayList<Class<?>>();
278 if(bundlesCache.containsKey(bundle.getSymbolicName())){
279
280 List<Class<?>> registedClasses = annotatedClassesMap.remove(bundle.getSymbolicName());
281 Class<?> clazz = null;
282 while(registedClasses != null && !registedClasses.isEmpty()){
283 clazz = registedClasses.remove(0);
284 gboatLoader.remove(clazz.getName());
285 }
286 }
287 bundlesCache.put(bundle.getSymbolicName(), bundle);
288
289 importPath = (String) bundle.getHeaders().get(MODEL_PACKAGE_HEADER);
290 if (StringUtils.isEmpty(importPath)) {
291 annotatedClassesMap.put(bundle.getSymbolicName(), importClasses);
292 continue;
293 } else {
294
295 logger.debug("dynamic import models : {}", importPath);
296 importItems = importPath.split(",");
297 for (String importItem : importItems) {
298
299 try {
300 Class<?> clazz = bundle.loadClass(importItem);
301 if (clazz != null) {
302 logger.debug("{} is a class", importItem);
303 importClasses.add(clazz);
304 continue;
305 }
306 } catch (ClassNotFoundException e1) {
307 logger.warn(e1.getMessage());
308 importClassNames = getClasses(importItem, bundle);
309 if (importClassNames.size() > 0) {
310 logger.debug("{} is a package, find classes in it is : {}", importItem, importClassNames);
311 for (String className : importClassNames) {
312 try {
313
314 importClasses.add(bundle.loadClass(className));
315 } catch (ClassNotFoundException e) {
316 logger.debug(e.getMessage(), e.getCause());
317 }
318 }
319 }
320 }
321 }
322
323
324 annotatedClassesMap.put(bundle.getSymbolicName(), importClasses);
325 }
326
327 for (Class<?> dealClass : importClasses) {
328 if (isEntity(dealClass)) {
329 registClasses.add(dealClass);
330 }
331
332 gboatLoader.add(dealClass.getName(), bundle);
333 }
334 }
335 bundlesToRegistPo.clear();
336 }
337 }
338
339
340
341
342
343
344
345 public static List<String> getClasses(String pack, Bundle bundle) {
346
347 List<String> classes = new ArrayList<String>();
348
349 String packageName = pack;
350 String packageDirName = packageName.replace('.', '/');
351 try {
352 URL url = bundle.getResource(packageDirName);
353 if (url == null)
354 return classes;
355
356 if (!"bundle".equals(url.getProtocol()))
357 return classes;
358
359
360 String filePath = bundle.getLocation().replaceFirst("file:(/|\\\\)", "");
361
362 ZipInputStream in = null;
363 try {
364 in = new ZipInputStream(new FileInputStream(filePath));
365 ZipEntry entry = null;
366 String name;
367 while ((entry = in.getNextEntry()) != null) {
368 if (!entry.isDirectory()) {
369 name = entry.getName();
370 if (name.startsWith(packageDirName) && name.endsWith(".class")) {
371 classes.add(name.substring(0, name.indexOf(".class")).replaceAll("/", "."));
372 }
373 }
374 }
375 } catch (IOException e) {
376 throw new ClassNotFoundException("error : " + packageName + " the jar file [" + bundle + "] can't find");
377 } finally {
378 IOUtils.closeQuietly(in);
379 }
380 } catch (Exception e) {
381 logger.error("获取 Bundle[{}] 的 [{}] 包下所有类名发生错误。", bundle.getSymbolicName(), pack);
382 logger.error("", e);
383 }
384 return classes;
385 }
386
387
388
389
390
391
392 private boolean isEntity(Class<?> c) {
393
394 if(c.isInterface() || c.isEnum() || c.isAnnotation())
395 return false;
396
397 Entity e = c.getAnnotation(Entity.class);
398 if (e != null)
399 return true;
400
401 c = c.getSuperclass();
402 if (null == c || c.getName().equals(Object.class.getName()))
403 return false;
404
405 return isEntity(c);
406 }
407
408 public void setBaseDAO(IBaseDAO baseDAO) {
409 this.baseDAO = baseDAO;
410 }
411
412 @Override
413 public void stop(BundleContext arg0) throws Exception {
414
415 }
416
417 }