一、 创建Plug-in Project工程,名为“PluginMgrCenter”,主要实现定时监控给定文件夹下jar包,对未加载的jar包进行加载
1、创建工程
2、工程结构如下图示意:
3、实现Activator类的方法,Activator类的作用,说白了就是该Bundle启动,停止会调用该类覆写的start(),stop()方法。
Activator类的start()方法中,保存osgi框架传进来的BundleContext对象,并启动一个定时任务。
代码如下:
package pluginmgrcenter; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import directwatcher.DirectWatcherTask; import directwatcher.ScheduleTimerPool; public class Activator implements BundleActivator { private static BundleContext bundleContext; public static BundleContext getBundleContext() { return bundleContext; } /* * (non-Javadoc) * * @see * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext * ) */ public void start(BundleContext context) throws Exception { bundleContext = context; try { DirectWatcherTask directWatcherTask = new DirectWatcherTask( bundleContext, "d:\\plugin\\"); ScheduleTimerPool.getInstance().schedule(directWatcherTask, 10000, 10000); } catch (Exception e) { e.printStackTrace(); } } /* * (non-Javadoc) * * @see * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ public void stop(BundleContext context) throws Exception { System.out.println("Bye World!"); } }4、ScheduleTimerPool.java类定义了一个简单的定时器。用于定时执行DirectWatcherTask.java中的jar包扫描任务。
package directwatcher; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class ScheduleTimerPool { private static ScheduleTimerPool scheduleTimerPool; static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(); public static final ScheduleTimerPool getInstance() { if (null == scheduleTimerPool) { scheduleTimerPool = new ScheduleTimerPool(); } return scheduleTimerPool; } private static Timer timer; public void schedule(TimerTask task, long deplay, long interval) { if (null == timer) { timer = new Timer(); } timer.schedule(task, deplay, interval); } }
5、DirectWatcherTask.java中run()方法实现了对指定路径的jar包进行扫描
a、如果发现该jar未被加载,则安装启动该jar包
b、如果该jar包版本有更新,则更新该jar包
代码如下:
* */ package directwatcher; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.TimerTask; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.Version; /** * @author Administrator * */ public class DirectWatcherTask extends TimerTask { private BundleContext bundleContext; public String bundleFolderPath; public DirectWatcherTask(BundleContext bundleContext, String bundleFolderPath) { super(); this.bundleContext = bundleContext; this.bundleFolderPath = bundleFolderPath; System.out.println("插件目录:" + bundleFolderPath); } @Override public void run() { try { if (bundleContext == null) { System.out.println("bundleContext is null"); return; } File folderInfo = new File(bundleFolderPath); // 如果目录不存在 if (!folderInfo.exists() || !folderInfo.isDirectory()) { System.out.println("bundleFloderPath is error!"); return; } File[] files = folderInfo.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { if (!pathname.isFile()) return false; return pathname.getName().toLowerCase().endsWith(".jar"); } }); List<Bundle> newBundleList = new ArrayList<Bundle>(); for (File file : files) { ZipFile zipFile = null; try { zipFile = new ZipFile(file); ZipEntry zipEntry = zipFile .getEntry("META-INF/MANIFEST.MF"); if (zipEntry == null || zipEntry.isDirectory()) continue; InputStream inputStream = zipFile.getInputStream(zipEntry); Properties prop = new Properties(); prop.load(inputStream); // 得到插件的名称和版本 String bundleName = prop.getProperty("Bundle-SymbolicName"); Version bundleVersion = Version.parseVersion(prop .getProperty("Bundle-Version")); Bundle preBundle = null; Bundle[] bundles = bundleContext.getBundles(); for (Bundle bundle : bundles) { if (bundle.getSymbolicName().equals(bundleName)) { preBundle = bundle; break; } } Bundle newBundle = null; // 如果之前没有此插件,则安装 if (preBundle == null) { System.out.println("自动安装新插件:" + bundleName + " " + bundleVersion); FileInputStream fileInputStream = new FileInputStream( file); newBundle = bundleContext.installBundle(file.getName(), fileInputStream); fileInputStream.close(); }// 否则更新 else { if (bundleVersion.compareTo(preBundle.getVersion()) > 0) { System.out.println("自动将插件:" + bundleName + " 由 " + preBundle.getVersion() + "更新到" + bundleVersion); FileInputStream fileInputStream = new FileInputStream( file); preBundle.update(fileInputStream); newBundle = preBundle; fileInputStream.close(); } } // 尝试启动插件 if (newBundle != null) { newBundleList.add(newBundle); } } catch (IllegalStateException ex) { continue; } catch (Exception ex) { ex.printStackTrace(); } finally { if (zipFile != null) { try { zipFile.close(); } catch (Exception ex) { ex.printStackTrace(); } } } } // 尝试启动所有的插件 boolean isAllBundleStartSuccess; for (int i = 0; i < newBundleList.size(); i++) { isAllBundleStartSuccess = true; for (Bundle newBundle : newBundleList) { if (newBundle.getState() != Bundle.ACTIVE && newBundle.getState() != Bundle.STARTING) { try { newBundle.start(); } catch (BundleException e) { isAllBundleStartSuccess = false; } } } if (isAllBundleStartSuccess) { break; } } // 启动尝试启动失败的插件以打印异常信息 for (Bundle newBundle : newBundleList) { if (newBundle.getState() != Bundle.ACTIVE && newBundle.getState() != Bundle.STARTING) { try { newBundle.start(); } catch (BundleException e) { e.printStackTrace(); } } } } catch (Exception e) { System.out.println("quickwebframework_web:插件自动管理线程接到线程中止命令,线程已终止!"); } } }
这样bundle管理Bundle已经成型了。
二:配置Myeclipse的“Run Configurations”
进入“Run Configurations”页面-->单击 OSGI Framework后点击“新建”图标-->选中新建的默认名称为“New_configuration”的Launch。
在“New_configuration”的Launch右侧的“Bundles”标签页,右方选择“Deselect ALL”后,在 Bundles选择框中选择“PluginMgrCenter” bundle,如下图示意:
然后在搜索栏中搜索“*osgi”进行搜索,搜索结果中选择“org.eclipse.osgi(3.5.1.R35x_v20090827)”如下:
3、创建Plug-In测试工程
1、创建工程名为“PluginAgent”的Plug-in工程,用于被Bundle管理Bundle管理,呵呵,是不是很拗口?本文的实验就是安装,启动,更新。
工程目录结构如下:
2、其中Activator.java如下,start()方法在控制台打印“hello pluginAgent!” stop()方法打印“bye pluginAgent!”
代码如下
package pluginagent; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { /* * (non-Javadoc) * * @see * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext * ) */ public void start(BundleContext context) throws Exception { System.out.println("hello pluginAgent!"); } /* * (non-Javadoc) * * @see * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ public void stop(BundleContext context) throws Exception { System.out.println("bye pluginAgent!"); } }
3、导出“PluginAgent”工程为“PluginAgent.jar”的jar包,路径为D:\plugin
四、测试
1、以第二步骤配置的 “New_configuration” Launch 运行。
2、执行“ss”命令,查询当前只有两个Bundle运行
3、等待控制台打印出“自动安装新插件:PluginAgent 1.0.0.qualifier”,则表示系统已经检测到“D:\plugin”目录下的jar包,并识别后开始加载。
4、“Hello pluginAgent”则表示PluginAgent.jar已经加载成功。
5、再次执行“ss”命令,观察到已经有“PluginAgent_1.0.0.qualifier”Bundle安装并且启动成功,状态为ACTIVE。
测试结果图示: