View Javadoc
1   /*
2    * $Id$
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package gboat2.admin.osgi.action;
23  
24  import java.io.ByteArrayOutputStream;
25  import java.io.File;
26  import java.io.FileInputStream;
27  import java.io.FileNotFoundException;
28  import java.io.FileOutputStream;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.io.OutputStream;
32  import java.io.PrintStream;
33  import java.lang.reflect.Method;
34  import java.util.ArrayList;
35  import java.util.Arrays;
36  import java.util.Collection;
37  import java.util.Collections;
38  import java.util.Comparator;
39  import java.util.Iterator;
40  import java.util.List;
41  import java.util.Map;
42  import java.util.Set;
43  import java.util.jar.Attributes;
44  import java.util.jar.JarFile;
45  import java.util.jar.Manifest;
46  
47  import javax.servlet.ServletContext;
48  import javax.servlet.http.HttpServletRequest;
49  
50  import org.apache.felix.shell.ShellService;
51  import org.apache.struts2.StrutsStatics;
52  import org.apache.struts2.convention.annotation.ResultPath;
53  import org.apache.struts2.osgi.BundleAccessor;
54  import org.apache.struts2.osgi.DefaultBundleAccessor;
55  import org.apache.struts2.osgi.OsgiHost;
56  import org.apache.struts2.osgi.StrutsOsgiListener;
57  import org.apache.struts2.util.ServletContextAware;
58  import org.osgi.framework.Bundle;
59  import org.osgi.framework.BundleContext;
60  import org.osgi.framework.BundleException;
61  import org.osgi.framework.ServiceReference;
62  import org.slf4j.Logger;
63  import org.slf4j.LoggerFactory;
64  
65  import com.opensymphony.xwork2.ActionContext;
66  import com.opensymphony.xwork2.ActionSupport;
67  import com.opensymphony.xwork2.config.Configuration;
68  import com.opensymphony.xwork2.config.entities.PackageConfig;
69  import com.opensymphony.xwork2.inject.Inject;
70  
71  /**
72   * 管理 Bundle 的 Action
73   * @date 2014-2-26
74   * @since 1.0
75   */
76  @ResultPath("/content")
77  //@gboat2.base.core.annotation.Module(name = "bundle管理", desc = "显示bundle列表及bundle的详细信息")
78  public class BundlesAction extends ActionSupport implements ServletContextAware {
79  
80      private static final long serialVersionUID = -1L;
81  
82      private final Logger logger = LoggerFactory.getLogger(BundlesAction.class.getName());
83  
84  	/** bundle 的 Bundle-SymbolicName 属性:{@value} */
85  	private static final String BUNDLE_SYMBOLIC_NAME = "Bundle-SymbolicName";
86  	
87  	/** 获得 webapp 的根目录 */
88  	public final static String WEB_APP_ROOT = System.getProperty("webapp.gboat2.root");
89  
90      /** class 文件存放目录 */
91      public final static String CLASS_LOCATION = "WEB-INF/classes/";
92  
93  	/** bundle存放目录 */
94  	public final static String BUNDLE_LOCATION = "WEB-INF/classes/bundles/";
95  
96  	/** bundle备份目录 */
97  	public final static String BACKUP_BUNDLES_LOCATION = "backup/";
98  
99  	private static final String INSTALL = "install";
100 
101     /**业务 Bundle 的级别 */
102     public final static String BUSINESS_LEVEL = "5" ;
103 
104 	//业务bundle路径
105 	public final static String FIVE_PATH = "bundles/5";
106 	public final static String FOUR_PATH = "bundles/4";
107 	public final static String THREE_PATH = "bundles/3";
108 	public final static String TWO_PATH = "bundles/2";
109 
110 	private transient BundleAccessor bundleAccessor;
111 
112     private transient OsgiHost osgiHost;
113 
114     private transient HttpServletRequest request = this.getRequest1();
115 
116     private String id;
117 
118 	private Configuration configuration;
119 
120 	private String bundleFlag;
121 
122 	private String output;
123 
124 	private String bundlePath;
125 
126 	private String message;
127 
128     /** 级别目录 */
129     private String level = "";
130 
131 	private String currentLevel;
132 
133 	/** 判断 安装 操作是否成功  */
134 	private boolean failure = false;
135 
136 	/** ftl 不支持 boolean 型,用这个变量替换一下 */
137 	private String failureString = "false";
138 
139     @Inject
140     public void setConfiguration(Configuration configuration) {
141         this.configuration = configuration;
142     }
143 
144     @Inject
145     public void setBundleAccessor(BundleAccessor bundleAccessor) {
146         this.bundleAccessor = bundleAccessor;
147     }
148 
149     @Override
150     public void setServletContext(ServletContext servletContext) {
151         osgiHost = (OsgiHost) servletContext.getAttribute(StrutsOsgiListener.OSGI_HOST);
152     }
153 
154     private HttpServletRequest getRequest1() {
155         return (HttpServletRequest) ActionContext.getContext().get(StrutsStatics.HTTP_REQUEST);
156     }
157 
158 	public String getFailureString() {
159 		return failureString;
160 	}
161 
162 	public void setFailureString(String failureString) {
163 		this.failureString = failureString;
164 	}
165 
166 	public boolean isFailure() {
167 		return failure;
168 	}
169 
170 	public void setFailure(boolean failure) {
171 		this.failure = failure;
172 	}
173 
174 	public String getCurrentLevel() {
175 		return currentLevel;
176 	}
177 
178 	public void setCurrentLevel(String currentLevel) {
179 		this.currentLevel = currentLevel;
180 	}
181 
182 	public String getLevel() {
183 		return level;
184 	}
185 
186 	public void setLevel(String level) {
187 		this.level = level;
188 	}
189 
190 	public String getMessage() {
191 		return message;
192 	}
193 
194 	public void setMessage(String message) {
195 		this.message = message;
196 	}
197 
198 	public HttpServletRequest getRequest() {
199 		return request;
200 	}
201 
202 	public void setRequest(HttpServletRequest request) {
203 		this.request = request;
204 	}
205 
206 	public String getBundlePath() {
207 		return bundlePath;
208 	}
209 
210 	public void setBundlePath(String bundlePath) {
211 		this.bundlePath = bundlePath;
212 	}
213 
214 	public String getOutput() {
215 		return output;
216 	}
217 
218 	public String getBundleFlag() {
219 		return bundleFlag;
220 	}
221 
222 	public void setBundleFlag(String bundleFlag) {
223 		this.bundleFlag = bundleFlag;
224 	}
225 
226     public String getId() {
227         return id;
228     }
229 
230     public void setId(String id) {
231         this.id = id;
232     }
233 
234     
235 	public String index() {
236 		return SUCCESS;
237 	}
238 
239 	public String view() {
240 		return SUCCESS;
241 	}
242 
243 	public String install() {
244 		return INSTALL;
245 	}
246 
247 	/**
248 	 * 启动 Bundle
249 	 * @return
250 	 * @throws BundleException 启动失败时抛出此异常
251 	 */
252 	public String start() throws BundleException {
253 		Bundle bundle = osgiHost.getBundles().get(id);
254 		try {
255 			bundle.start();
256 			//start() fires a BundleEvent.STARTED, which loads the config
257 			//we need to wait until the config is loaded from that bundle but
258 			//there no easy way/elegant way to know if the bundle was processed already
259 			Thread.sleep(1000);
260 		} catch (Exception e) {
261 			addActionError(e.toString());
262 			logger.error(e.getMessage(),e.getCause());
263 		}
264 
265 		return view();
266 	}
267 
268 	/**
269 	 * 停止 Bundle
270 	 * @return
271 	 * @throws BundleException 停止 Bundle 发生异常时,抛出此异常
272 	 */
273 	public String stop() throws BundleException {
274 		Bundle bundle = osgiHost.getBundles().get(id);
275 		try {
276 			bundle.stop();
277 		} catch (Exception e) {
278 			addActionError(e.toString());
279 			logger.error(e.getMessage(),e.getCause());
280 		}
281 
282 		return view();
283 	}
284 	
285 	/**
286 	 * 通过命令来实现更新操作,直接点击 bundle 进行刷新操作
287 	 * @return
288 	 * @throws BundleException
289 	 */
290 	public String refresh() throws BundleException {
291 		Bundle bundle = osgiHost.getBundles().get(id);
292 		
293 		// 设置当前bundle的级别
294 		setCurrentLevel(getBoundLevel(bundle.getLocation()));
295 		
296 		if(BUSINESS_LEVEL.equals(getCurrentLevel())){
297 			update(); // 更新
298 		}else{
299 			executeCommond(" refresh " + bundle.getBundleId());
300 		}
301 		
302 		return view();
303 	}
304 
305 	/**
306 	 * 通过命令来实现更新操作
307 	 * @return
308 	 * @throws BundleException
309 	 */
310 	public String refreshWithPara(Bundle bundle) throws BundleException {
311 		executeCommond(" refresh " + bundle.getBundleId());
312 		return view();
313 	}
314 
315 	/**
316 	 * 更新 Bundle 的状态
317 	 * @return
318 	 * @throws BundleException
319 	 */
320 	public String update() throws BundleException {
321 		Bundle bundle = osgiHost.getBundles().get(id);
322 		try {
323 			bundle.update();
324 		} catch (Exception e) {
325 			addActionError(e.toString());
326 			logger.error(e.getMessage(),e.getCause());
327 		}
328 
329 		return view();
330 	}
331 
332 	/**
333 	 * 检查是否存在指定名称的 Bundle,存在则返回对应的 Bundle,反之则返回 null。<br>
334 	 * 相应的 bundle 在对应级别的目录存在,但通过 shell 命令把他卸载了,这种情况返回 false
335 	 * @param symbolicName Bundle 的名称(唯一标识)
336 	 * @throws BundleException
337 	 */
338 	private Bundle isExistThisBundle(String symbolicName) throws BundleException {
339 		//如果symbolicName为空不做任何操作
340 		List<Bundle> bundles = new ArrayList<Bundle>(osgiHost.getBundles().values());
341 		Bundle bundle = null;
342 		for (Iterator<Bundle> iterator = bundles.iterator(); iterator.hasNext();) {
343 			bundle = iterator.next();
344 			if (bundle.getSymbolicName().equals(symbolicName)) {
345 				return bundle;
346 			}
347 		}
348 		return null;
349 	}
350 
351 	/**
352 	 * 检查 Bundle 是否为 Struts Bundle
353 	 * @param bundle
354 	 * @return
355 	 */
356 	public boolean isStrutsEnabled(Bundle bundle) {
357 		return "true".equalsIgnoreCase((String) bundle.getHeaders().get(OsgiHost.OSGI_HEADER_STRUTS_ENABLED));
358 	}
359 
360 	/**
361 	 * 通过 Bundle 的 ID 获取对应的 Bundle 实例
362 	 * @return
363 	 */
364 	public Bundle getBundle() {
365 		return osgiHost.getBundles().get(id);
366 	}
367 
368 	/**
369 	 * 获取指定 Bundle 下 Struts.xml 配置文件中的的所有 package
370 	 * @return
371 	 */
372 	public List<PackageConfig> getPackages() {
373 		List<PackageConfig> pkgs = new ArrayList<PackageConfig>();
374 		Bundle bundle = getBundle();
375 		if (bundle.getState() == Bundle.ACTIVE) {
376 		    Set<String> packages = bundleAccessor.getPackagesByBundle(bundle);
377 			if (packages == null)
378 				return pkgs;
379 			
380 			PackageConfig packageConfig = null;
381 			for (String name : packages) {
382 				packageConfig = configuration.getPackageConfig(name);
383 				if (packageConfig != null)
384 					pkgs.add(packageConfig);
385 			}
386 		}
387 		return pkgs;
388 	}
389 	
390 	public String getNoData(){
391 		Object serv = getModuleService();
392 		//正在执行刷新操作
393 		if(serv == null){
394 			return "正在执行更新操作,请稍后。。。。30秒左右后,请点击页面的【refresh】按钮,查看更新后bundle的最新信息";
395 		}
396 		
397 		return null;
398 	}
399 	
400 	/**
401 	 * 获取指定 Bundle 下的所有 module
402 	 * @return
403 	 * @throws NoSuchMethodException 
404 	 * @throws SecurityException 
405 	 */
406 	public Object getModules() {
407 		String bundleName = getBundleName();
408 		Object serv = getModuleService();
409 		// 正在执行刷新操作
410 		if(serv == null){
411 		   return  new ArrayList<Object>();
412 		}
413 		
414 		Method method = null;
415 		Object result = null;; 
416 		try {
417 			method = serv.getClass().getMethod("getModuleListByBundleName", String.class);
418 			method.setAccessible(true);
419 			result = method.invoke(serv, bundleName);
420 		} catch (Exception e) {
421 		    result = new ArrayList<Object>();
422 			logger.trace("获取 Bundle[{}] 下的所有 Module 失败!\r\n{}", bundleName, e.getStackTrace());
423 		}
424 		return result;
425 	}
426 
427 	/**
428 	 * 获取指定 Bundle 下的所有 operation
429 	 * @return
430 	 */
431 	public Object getOperations() {
432 		String bundleName = getBundleName();
433 		Object serv = getModuleService();
434 		if(serv == null)
435            return  new ArrayList<Object>();
436 	    
437 		Method method = null;
438 		Object result = null;
439 		try {
440 			method = serv.getClass().getMethod("getOperaByBundleAddAction", String.class, String.class);
441 			method.setAccessible(true);
442 			result = method.invoke(serv, bundleName, this.getClass().getName());
443 		} catch (Exception e) {
444 		    result = new ArrayList<Object>(); 
445 		    logger.trace("获取 Bundle[{}] 下的所有 Operation 失败!\r\n{}", bundleName, e.getStackTrace());
446 		}
447 		
448 		return result;
449 	}
450 
451 	/**
452 	 * @return Bundle 的头信息的所有 key
453 	 */
454 	public ArrayList<String> getHeaderKeys() {
455 		return Collections.list(getBundle().getHeaders().keys());
456 	}
457 
458 	/**
459 	 * 根据条件查询 bundle:全部,系统,业务
460 	 * @return
461 	 */
462 	public Collection<Bundle> getBundles() {
463 		if ("ALL".equals(getBundleFlag()) || "".equals(getBundleFlag())) {
464 			return getAllBundles();
465 		}
466 		if ("SYSTEM".equals(getBundleFlag())) {
467 			return getSystemBundles();
468 		}
469 		if ("BUSINESS".equals(getBundleFlag())) {
470 			return getBusinessBundles();
471 		}
472 
473 		return Collections.emptyList();
474 	}
475 
476 	/**
477 	 * 获取所有 Bundle
478 	 * @return 所有 Bundle
479 	 */
480 	private Collection<Bundle> getAllBundles() {
481 		List<Bundle> bundles = new ArrayList<Bundle>(osgiHost.getBundles().values());
482 		bundleSort(bundles);
483 		return bundles;
484 	}
485 
486 	/**
487 	 * 获取系统 bundle
488 	 * @return 系统 bundle
489 	 */
490 	private Collection<Bundle> getSystemBundles() {
491 		List<Bundle> systemBundles = new ArrayList<Bundle>();
492 
493 		Collection<Bundle> bundles = getAllBundles();
494 		for (Iterator<Bundle> iterator = bundles.iterator(); iterator.hasNext();) {
495 			Bundle bundle = (Bundle) iterator.next();
496 			String location = bundle.getLocation();
497 			location = replaceSeparator(location);
498 			if (!(location.indexOf(FIVE_PATH) > 0)) {
499 				systemBundles.add(bundle);
500 			}
501 		}
502 
503 		bundleSort(systemBundles);
504 		return systemBundles;
505 	}
506 
507 	/**
508 	 * 获取业务bundle
509 	 * @return 业务bundle
510 	 */
511 	private Collection<Bundle> getBusinessBundles() {
512 		List<Bundle> businessBundles = new ArrayList<Bundle>();
513 
514 		Collection<Bundle> bundles = getAllBundles();
515 		for (Iterator<Bundle> iterator = bundles.iterator(); iterator.hasNext();) {
516 			Bundle bundle = (Bundle) iterator.next();
517 			String location = bundle.getLocation();
518 			location = replaceSeparator(location);
519 			if (location.indexOf(FIVE_PATH) > 0) {
520 				businessBundles.add(bundle);
521 			}
522 		}
523 
524 		bundleSort(businessBundles);
525 		return businessBundles;
526 	}
527 
528 	/**
529 	 * bundle排序,排序规则为先将 Struts Bundle 排前面,然后根据 Bundle 的名称升序
530 	 * @param 排序后的 Bundle 集合
531 	 */
532 	private void bundleSort(List<Bundle> businessBundles) {
533 		Collections.sort(businessBundles, new Comparator<Bundle>() {
534 			public int compare(Bundle bundle1, Bundle bundle2) {
535 				boolean bundle1StrutsEnabled = isStrutsEnabled(bundle1);
536 				boolean bundle2StrutsEnabled = isStrutsEnabled(bundle2);
537 				if ((bundle1StrutsEnabled && bundle2StrutsEnabled) || (!bundle1StrutsEnabled && !bundle2StrutsEnabled))
538 					return bundle1.getSymbolicName().compareTo(bundle2.getSymbolicName());
539 				else {
540 					return bundle1StrutsEnabled ? -1 : 1;
541 				}
542 			}
543 		});
544 	}
545 
546 	/**
547 	 * 添加或者更新bundle前,上传 Bundle 的 jar 包
548 	 * @return
549 	 */
550 	public String upload() {
551 		ActionContext context = ActionContext.getContext();
552 		Map<String, ?> params = context.getParameters();
553 		File[] file = (File[]) params.get("uploadFile");
554 		String[] fileNames = (String[]) params.get("uploadFileFileName");
555 
556 		if (file == null)
557 			return checkFileIsNull();
558 
559 		if (file.length > 0) {
560 			String fileName = fileNames[0];
561 			if (!fileName.endsWith(".jar")) {
562 				this.message = "请上传.jar的文件";
563 				this.failure = true;
564 				this.failureString = "true";
565 				return INSTALL;
566 			}
567 
568 			String pathname = getRealBusinessBundlePath() + File.separator + fileName;
569 			File outFile = new File(pathname);
570 			setBundlePath(pathname);
571 
572 			//判断上传的bundle是否已经存在,若存在返回List:备份文件路径和存在的文件
573 			List<Object> jarExistPath = jarExistPath(fileName);
574 
575 			//此为第一种情况,不存在当前上传的bundle
576 			if (jarExistPath == null) {
577 				//增加
578 				failure = addOrUpdateJar(file, failure, outFile);
579 				//启动
580 				startBundle();
581 				this.message = failure ? "安装bundle失败,请查看日志,确定具体原因" : "安装bundle成功";
582 				setCurrentLevel(level);
583 				return INSTALL;
584 
585 			} else {
586 				//存在当前bundle
587 
588 				//备份文件名称
589 				String backupName = (String) jarExistPath.get(0);
590 				//需要备份的文件
591 				File oldFile = (File) jarExistPath.get(1);
592 				//备份文件路径
593 				String backupPath = (String) jarExistPath.get(2);
594 
595 				//需要备份文件的路径
596 				String oldFilePath = (String) jarExistPath.get(3);
597 
598 				//备份文件路径文件
599 				File backupFilePath = new File(backupPath);
600 
601 				//路径不存在,创建路径
602 				if (!backupFilePath.exists()) {
603 					boolean mkdirs = backupFilePath.mkdirs();
604 					if (!mkdirs) {
605 						throw new RuntimeException(" create directory  {" + backupFilePath + "}  fail ");
606 					}
607 				}
608 
609 				//创建备份文件
610 				File backupOutFile = new File(backupPath, backupName);
611 
612 				//备份
613 				failure = addOrUpdateJar(new File[] { oldFile }, failure, backupOutFile);
614 				if (failure) {
615 					message = "备份bundle失败";
616 					return INSTALL;
617 				}
618 				//更新
619 				failure = addOrUpdateJar(file, failure, oldFile);
620 				if (failure) {
621 					message = "更新bundle失败";
622 					return INSTALL;
623 				}
624 				
625 				try {
626 					
627 					//更新时,级别与原来bundle所在的级别一致
628 					setCurrentLevel(getBoundLevel(oldFilePath));
629 					
630 					String bundleSymbolicName = getBundleSymbolicName(oldFilePath);
631 					
632 					Bundle existThisBundle = isExistThisBundle(bundleSymbolicName);
633 					
634 					if (existThisBundle!=null) {
635 						//业务bundle,只负责update,此为第二种情况
636 						if(getCurrentLevel().equals(BUSINESS_LEVEL)){
637 //							existThisBundle.update();
638 							refreshWithPara(existThisBundle);
639 							this.message = "更新bundle成功";
640 						}
641 						//业务bundle,只负责update和刷新,此为第三种情况
642 						if(!getCurrentLevel().equals(BUSINESS_LEVEL)){
643 							//先执行更新,然后执行刷新
644 //							existThisBundle.update();
645 //							Thread.sleep(5 * 1000);
646 							refreshWithPara(existThisBundle);
647 							this.message = "更新bundle,并刷新bundle,此种情况比较费时间,为了安全性,请等一分钟后再做其他操作";
648 						}
649 						
650 					}
651 					//此为第四种情况,只安装	
652 					else {
653 						//执行安装命令
654 						installBundle(oldFilePath,bundleSymbolicName);
655 						this.message = "安装bundle成功";
656 					}
657 
658 				} catch (BundleException e) {
659 					failure = true;
660 					this.failureString = "true";
661 					message = "更新bundle出现了错误";
662 					logger.error(e.getMessage(), e);
663 				}
664 
665 				return INSTALL;
666 			}
667 		}
668 
669 		return INSTALL;
670 	}
671 
672 	/**
673 	 * 更新时取当前bundle的级别
674 	 * @param bundlepath
675 	 * @return
676 	 */
677 	private String getBoundLevel(String bundlepath) {
678 		bundlepath = replaceSeparator(bundlepath);
679 		if (bundlepath.indexOf(FIVE_PATH) > 0) {
680 			return FIVE_PATH.substring(FIVE_PATH.lastIndexOf("/") + 1);
681 		}
682 		if (bundlepath.indexOf(FOUR_PATH) > 0) {
683 			return FOUR_PATH.substring(FOUR_PATH.lastIndexOf("/") + 1);
684 		}
685 		if (bundlepath.indexOf(THREE_PATH) > 0) {
686 			return THREE_PATH.substring(THREE_PATH.lastIndexOf("/") + 1);
687 		}
688 		if (bundlepath.indexOf(TWO_PATH) > 0) {
689 			return TWO_PATH.substring(TWO_PATH.lastIndexOf("/") + 1);
690 		}
691 
692 		return null;
693 	}
694 
695 	private boolean addOrUpdateJar(File[] file, boolean flag, File outFile) {
696 		try {
697 			InputStream inStream = new FileInputStream(file[0]);
698 			OutputStream outStream = new FileOutputStream(outFile);
699 			byte[] b = new byte[1024];
700 			int len = 0;
701 			while ((len = inStream.read(b)) != -1) {
702 				outStream.write(b, 0, len);
703 			}
704 			outStream.close();
705 			inStream.close();
706 		} catch (FileNotFoundException e1) {
707 			flag = true;
708 			this.failureString = "true";
709 			logger.error(e1.getMessage(), e1.getCause());
710 		} catch (IOException e) {
711 			flag = true;
712 			this.failureString = "true";
713 			logger.error(e.getMessage(), e.getCause());
714 		}
715 		return flag;
716 	}
717 
718 	/**
719 	 * 启动 Bundle
720 	 * @return
721 	 */
722 	private String startBundle() {
723 		executeCommond("start   file:/" + this.getBundlePath());
724 		return INSTALL;
725 	}
726 
727 	/**
728 	 * 安装;对于被卸载的bundle只负责安装,不做其他任何操作
729 	 * @return
730 	 */
731 	private String installBundle(String oldFilePath,String bundleSymbolicName)  throws BundleException{
732 		executeInstall(oldFilePath);
733 		return INSTALL;
734 	}
735 
736 	private void executeInstall(String oldFilePath) {
737 		executeCommond(" install   file:/" + oldFilePath);
738 	}
739 
740 	/**
741 	 * 执行 Felix 命令
742 	 * @param command 要执行的命令
743 	 */
744 	private void executeCommond(String command) {
745 		System.setProperty("java.protocol.handler.pkgs", "org.ops4j.pax.url.assembly");
746 
747 		// get service
748 		ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
749 		ByteArrayOutputStream errByteStream = new ByteArrayOutputStream();
750 		PrintStream outStream = new PrintStream(outByteStream);
751 		PrintStream errStream = new PrintStream(errByteStream);
752 
753 		String outString = null;
754 		String errString = null;
755 		try {
756 			//这个方法抛出的异常都被catch掉了
757 			executeCommand(command, outStream, errStream);
758 			outString = outByteStream.toString().trim();
759 			errString = errByteStream.toString().trim();
760 		} catch (Exception e) {
761 			errString = e.getMessage();
762 			logger.error(e.getMessage(), e.getCause());
763 			message = errString;
764 		} finally {
765 			outStream.close();
766 			errStream.close();
767 		}
768 
769 		output = errString != null && errString.length() > 0 ? errString : outString;
770 	}
771 
772 	/**
773      * 执行 Felix 的 shell 命令
774      * @param commandLine 命令行的内容,包括命令及其参数
775      * @param out 标准信息输出流
776      * @param err 错误信息输出流
777      * @throws Exception 执行 shell 命令发生错误时,抛出异常
778      */
779 	private void executeCommand(String commandLine, PrintStream out, PrintStream err) throws Exception {
780 		ShellService shellService = getShellService();
781 		if (shellService != null)
782 			shellService.executeCommand(commandLine, out, err);
783 		else
784 			err.println("Apache Felix Shell service is not installed");
785 	}
786 
787 	public String displayProperty(Object obj) {
788 		if (obj.getClass().isArray()) {
789 			return Arrays.asList((Object[]) obj).toString();
790 		} else {
791 			return obj.toString();
792 		}
793 	}
794 
795 	/**
796 	 * 获取 Bundle 的状态字符串
797 	 * @param bundle
798 	 * @return
799 	 */
800 	public String getBundleState(Bundle bundle) {
801 		switch (bundle.getState()) {
802 			case Bundle.ACTIVE:
803 				return "Active";
804 			case Bundle.INSTALLED:
805 				return "Installed";
806 			case Bundle.RESOLVED:
807 				return "Resolved";
808 			case Bundle.STARTING:
809 				return "Starting";
810 			case Bundle.STOPPING:
811 				return "Stopping";
812 			case Bundle.UNINSTALLED:
813 				return "Uninstalled";
814 			default:
815 				throw new IllegalStateException("Invalid state");
816 		}
817 	}
818 
819 	/**
820 	 * 判断 Bundle 是否可以执行指定的操作
821 	 * @param bundle 要进行操作的 Bundle
822 	 * @param val 要进行操作的命令,如:start、stop、update 等
823 	 * @return 可以执行指定的操作,则返回 true,反之则返回 false
824 	 */
825 	public boolean isAllowedAction(Bundle bundle, String val) {
826 		int state = -1;
827 		try {
828 			state = bundle.getState();
829 		} catch (Exception e) {
830 			addActionError("Unable to determine bundle state: " + e.getMessage());
831 			return false;
832 		}
833 
834 		if ("start".equals(val)) {
835 			return state == Bundle.RESOLVED;
836 		} else if ("stop".equals(val)) {
837 			return state == Bundle.ACTIVE;
838 		} else if ("update".equals(val)) {
839 			return state == Bundle.ACTIVE || state == Bundle.INSTALLED || state == Bundle.RESOLVED;
840 		}
841 		throw new IllegalArgumentException("Invalid state");
842 	}
843 
844 	/**
845 	 * 获取 module 服务
846 	 * @return {@code gboat2.base.core.service.IModuleService} 接口的实例
847 	 */
848 	private Object getModuleService() {
849 		BundleContext bundleContext = osgiHost.getBundleContext();
850 		ServiceReference<?> servReference = bundleContext.getServiceReference("gboat2.base.core.service.IModuleService");
851 		return servReference == null ? null :  bundleContext.getService(servReference);
852 	}
853 
854 	/**
855 	 * 校验 上传的文件不能为空
856 	 * @param file
857 	 * @return
858 	 */
859 	private String checkFileIsNull() {
860 		this.message = "上传的bundle不能为空,请选择要上传的bundle";
861 		this.failure = true;
862 		this.failureString = "true";
863 		return INSTALL;
864 	}
865 
866 	/**
867 	 * 获取 bundle 的名称
868 	 * @return
869 	 */
870 	private String getBundleName() {
871 		return osgiHost.getBundles().get(id).getSymbolicName();
872 	}
873 
874 	/**
875 	 * 获取 Bundle 的物理路径
876 	 * @return
877 	 */
878 	private String getRealBusinessBundlePath() {
879 		String path = WEB_APP_ROOT + BUNDLE_LOCATION + level;
880 		File pathDir = new File(path);
881 		if (!pathDir.exists()) {
882 			boolean mkdirs = pathDir.mkdirs();
883 			if (!mkdirs) {
884 				throw new RuntimeException(" create directory  {" + path + "}  fail ");
885 			}
886 		} else if (!pathDir.isDirectory()) {
887 			throw new RuntimeException(path + " should be directory");
888 		}
889 		return path;
890 	}
891 	
892 	/**
893 	 * 业务bundle4备份地址
894 	 * @return
895 	 */
896 	private String getRealFiveBundlePath_() {
897 		return WEB_APP_ROOT + BACKUP_BUNDLES_LOCATION + FIVE_PATH;
898 	}
899 
900 	/**
901 	 * 业务bundle4备份地址
902 	 * @return
903 	 */
904 	private String getRealFourBundlePath_() {
905 		return WEB_APP_ROOT + BACKUP_BUNDLES_LOCATION + FOUR_PATH;
906 	}
907 
908 	/**
909 	 * 系统bundle3备份地址
910 	 * @return
911 	 */
912 	private String getRealThreeBundlePath() {
913 		return WEB_APP_ROOT + BACKUP_BUNDLES_LOCATION + THREE_PATH;
914 	}
915 
916 	/**
917 	 * 系统bundle2备份地址
918 	 * @return
919 	 */
920 	private String getRealTwoBundlePath() {
921 		return WEB_APP_ROOT + BACKUP_BUNDLES_LOCATION + TWO_PATH;
922 	}
923 
924 	/**
925 	 * 业务bundle地址
926 	 * @return
927 	 */
928 	private String getRealFourBundlePathT() {
929 		return WEB_APP_ROOT + CLASS_LOCATION + FOUR_PATH;
930 	}
931 	
932 	/**
933 	 * 业务bundle地址
934 	 * @return
935 	 */
936 	private String getRealFiveBundlePathT() {
937 		return WEB_APP_ROOT + CLASS_LOCATION + FIVE_PATH;
938 	}
939 
940 	/**
941 	 * 系统bundle3地址
942 	 * @return
943 	 */
944 	private String getRealThreeBundlePathT() {
945 		return WEB_APP_ROOT + CLASS_LOCATION + THREE_PATH;
946 	}
947 
948 	/**
949 	 * 系统bundle2地址
950 	 * @return
951 	 */
952 	private String getRealTwoBundlePathT() {
953 		return WEB_APP_ROOT + CLASS_LOCATION + TWO_PATH;
954 	}
955 
956 	/**
957 	 * 获得felix服务
958 	 * @return
959 	 */
960 	private ShellService getShellService() {
961 		//bundle can be de-activated, so keeping a reference aorund is not a good idea
962 		DefaultBundleAccessor bundleAcessor = DefaultBundleAccessor.getInstance();
963 		ServiceReference<?> ref = bundleAcessor.getServiceReference(ShellService.class.getName());
964 		return (ShellService) bundleAcessor.getService(ref);
965 	}
966 
967 	/**
968 	 * 判断当前上传的jar是否在系统bundle2,3和业务bundle目录下已经存在,若存在返回当前存在的bundle目录
969 	 * @param uploadFileName
970 	 * @return
971 	 */
972 	private List<Object> jarExistPath(String uploadFileName) {
973 		List<Object> list = new ArrayList<Object>();
974 		
975 		File jar5 = new File(getRealFiveBundlePathT());
976 		File[] jar5Array = jar5.listFiles();
977 		
978 		File jar4 = new File(getRealFourBundlePathT());
979 		File[] jar4Array = jar4.listFiles();
980 		File jar3 = new File(getRealThreeBundlePathT());
981 		File[] jar3Array = jar3.listFiles();
982 		File jar2 = new File(getRealTwoBundlePathT());
983 		File[] jar2Array = jar2.listFiles();
984 
985 		if (jar5Array != null) {
986 			for (int i = 0; i < jar5Array.length; i++) {
987 				File jarFile = jar5Array[i];
988 				if (uploadFileName.equals(jarFile.getName())) {
989 					list.add(getBackupJarFileName(jarFile.getName()));
990 					list.add(jarFile);
991 					list.add(getRealFiveBundlePath_());
992 					list.add(replaceSeparator(jarFile.getPath()));
993 					return list;
994 				}
995 			}
996 		}
997 		
998 		if (jar4Array != null) {
999 			for (int i = 0; i < jar4Array.length; i++) {
1000 				File jarFile = jar4Array[i];
1001 				if (uploadFileName.equals(jarFile.getName())) {
1002 					list.add(getBackupJarFileName(jarFile.getName()));
1003 					list.add(jarFile);
1004 					list.add(getRealFourBundlePath_());
1005 					list.add(replaceSeparator(jarFile.getPath()));
1006 					return list;
1007 				}
1008 			}
1009 		}
1010 		if (jar3Array != null) {
1011 			for (int i = 0; i < jar3Array.length; i++) {
1012 				File jarFile = jar3Array[i];
1013 				if (uploadFileName.equals(jarFile.getName())) {
1014 					list.add(getBackupJarFileName(jarFile.getName()));
1015 					list.add(jarFile);
1016 					list.add(getRealThreeBundlePath());
1017 					list.add(replaceSeparator(jarFile.getPath()));
1018 					return list;
1019 				}
1020 			}
1021 		}
1022 
1023 		if (jar2Array != null) {
1024 			for (int i = 0; i < jar2Array.length; i++) {
1025 				File jarFile = jar2Array[i];
1026 				if (uploadFileName.equals(jarFile.getName())) {
1027 					list.add(getBackupJarFileName(jarFile.getName()));
1028 					list.add(jarFile);
1029 					list.add(getRealTwoBundlePath());
1030 					list.add(replaceSeparator(jarFile.getPath()));
1031 					return list;
1032 				}
1033 			}
1034 		}
1035 
1036 		//上传的bundle为新bundle
1037 		return null;
1038 	}
1039 
1040 	/**
1041 	 * 为备份jar包增加时间戳
1042 	 * @param jarName
1043 	 * @return
1044 	 */
1045 	private String getBackupJarFileName(String jarName) {
1046 		String name = jarName.substring(0, jarName.lastIndexOf("."));
1047 		return name + "_" + System.currentTimeMillis() + jarName.substring(jarName.lastIndexOf("."), jarName.length());
1048 
1049 	}
1050 
1051 	private String replaceSeparator(String path) {
1052 		return path.replace(File.separator, "/");
1053 	}
1054 
1055 	/**
1056 	 * 根据 Bundle 的 jar 文件路径获取 Bundle 的名称
1057 	 * @param filePath jar 文件路径
1058 	 * @return 对应的 Bundle 的名称
1059 	 */
1060 	private String getBundleSymbolicName(String filePath) {
1061 		if (filePath == null || filePath.equals("") || !filePath.endsWith(".jar")) {
1062 			return null;
1063 		}
1064 		try {
1065 			JarFile jf = new JarFile(filePath);
1066 			Manifest mf = jf.getManifest();
1067 			Attributes attributes = mf.getMainAttributes();
1068 			String bundleSymbolicName = attributes.getValue(BUNDLE_SYMBOLIC_NAME);
1069 			if (bundleSymbolicName != null && !bundleSymbolicName.equals("")) {
1070 				bundleSymbolicName = bundleSymbolicName.split(";")[0];
1071 				if (bundleSymbolicName != null && !bundleSymbolicName.equals("")) {
1072 					return bundleSymbolicName;
1073 				}
1074 			}
1075 			return null;
1076 		} catch (IOException e) {
1077 			return null;
1078 		}
1079 	}
1080 }