一、 创建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。
测试结果图示: