1、输入检测服务 Bundle
在下面的例子中,我们定义了一个名称为 SpellChecker 的服务,该服务将使用我们注册的所有字典服务来检测用户输入的单词是否正确,而且 SpellChecker 只有在至少有一个字典服务是有效的时候才能被使用,下面是 SpellChecker 接口的定义:
/*
* Apache Felix OSGi tutorial.
**/
package tutorial.example6.service;
/**
* 检测用户输入的一串字符串是否正确。
**/
public interface SpellChecker
{
/**
* Checks a given passage for spelling errors. A passage is any
* number of words separated by a space and any of the following
* punctuation marks: comma (,), period (.), exclamation mark (!),
* question mark (?), semi-colon (;), and colon(:).
* @param passage the passage to spell check.
* @return An array of misspelled words or null if no
* words are misspelled.
**/
public String[] check(String passage);
}
在下面 bundle 的源代码中,我们需要创建一个字典服务集合,其中包含了当前可用的所有字典服务,并且当发现新的可用的字典服务的时候将其添加到此集合,当旧的某个服务不可用了需要将其移除集合。除此之外,我们还需要在字典服务从有到无的时候使 SpellChecker 失效,也就是取消注册,当字典服务集合从无变有的时候重新注册 SpellChecker 服务。最后,为了监控字典服务的注册与注销,我们需要将将此 Bundle 自身作为服务监听者注册到系统,具体实现代码如下:
/*
* Apache Felix OSGi tutorial.
**/
package tutorial.example6;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceEvent;
import tutorial.example2.service.DictionaryService;
import tutorial.example6.service.SpellChecker;
/**
* 提供了 SpellChecker 的实现,在 SpellChecker 的实现中,我们使用系统所有的字典服务检测用户输入的单词是否正确。
* Acticator 中除监测字典服务之外,还实现了动态将新发现的字典服务添加到此 bundle 维护的字典服务集合中,将失效的
* 字典服务移除此 bundle 维护的字典服务集合,当字典服务集合中字典服务从有到无的时候,此 bundle 需要取消 SpellChecker
* 字典服务的注册,当字典服务集合中字典服务从无到有的时候,此 bundle 需要重新将 SpellChecker 注册到 OSGI 框架中。
**/
public class Activator implements BundleActivator, ServiceListener
{
// Bundle's context.
private BundleContext m_context = null;
// List of available dictionary service references.
private ArrayList m_refList = new ArrayList();
// Maps service references to service objects.
private HashMap m_refToObjMap = new HashMap();
// The spell checker service registration.
private ServiceRegistration m_reg = null;
/**
* Implements BundleActivator.start(). Adds itself
* as a service listener and queries for all currently
* available dictionary services. Any available dictionary
* services are added to the service reference list. If
* dictionary services are found, then the spell checker
* service is registered.
* @param context the framework context for the bundle.
**/
public void start(BundleContext context) throws Exception
{
m_context = context;
synchronized (m_refList)
{
// Listen for events pertaining to dictionary services.
m_context.addServiceListener(this,
"(&(objectClass=" + DictionaryService.class.getName() + ")" +
"(Language=*))");
// Query for all dictionary services.
ServiceReference[] refs = m_context.getServiceReferences(
DictionaryService.class.getName(), "(Language=*)");
// Add any dictionaries to the service reference list.
if (refs != null)
{
for (int i = 0; i < refs.length; i++)
{
// Get the service object.
Object service = m_context.getService(refs[i]);
// Make that the service is not being duplicated.
if ((service != null) &&
(m_refToObjMap.get(refs[i]) == null))
{
// Add to the reference list.
m_refList.add(refs[i]);
// Map reference to service object for easy look up.
m_refToObjMap.put(refs[i], service);
}
}
// Register spell checker service if there are any
// dictionary services.
if (m_refList.size() > 0)
{
m_reg = m_context.registerService(
SpellChecker.class.getName(),
new SpellCheckerImpl(), null);
}
}
}
}
/**
* Implements BundleActivator.stop(). Does nothing since
* the framework will automatically unregister any registered services,
* release any used services, and remove any event listeners.
* @param context the framework context for the bundle.
**/
public void stop(BundleContext context)
{
// NOTE: The services automatically released.
}
/**
* Implements ServiceListener.serviceChanged(). Monitors
* the arrival and departure of dictionary services, adding and
* removing them from the service reference list, respectively.
* In the case where no more dictionary services are available,
* the spell checker service is unregistered. As soon as any dictionary
* service becomes available, the spell checker service is
* reregistered.
* @param event the fired service event.
**/
public void serviceChanged(ServiceEvent event)
{
synchronized (m_refList)
{
// Add the new dictionary service to the service list.
if (event.getType() == ServiceEvent.REGISTERED)
{
// Get the service object.
Object service = m_context.getService(event.getServiceReference());
// Make that the service is not being duplicated.
if ((service != null) &&
(m_refToObjMap.get(event.getServiceReference()) == null))
{
// Add to the reference list.
m_refList.add(event.getServiceReference());
// Map reference to service object for easy look up.
m_refToObjMap.put(event.getServiceReference(), service);
// Register spell checker service if necessary.
if (m_reg == null)
{
m_reg = m_context.registerService(
SpellChecker.class.getName(),
new SpellCheckerImpl(), null);
}
}
else if (service != null)
{
m_context.ungetService(event.getServiceReference());
}
}
// Remove the departing service from the service list.
else if (event.getType() == ServiceEvent.UNREGISTERING)
{
// Make sure the service is in the list.
if (m_refToObjMap.get(event.getServiceReference()) != null)
{
// Unget the service object.
m_context.ungetService(event.getServiceReference());
// Remove service reference.
m_refList.remove(event.getServiceReference());
// Remove service reference from map.
m_refToObjMap.remove(event.getServiceReference());
// If there are no more dictionary services,
// then unregister spell checker service.
if (m_refList.size() == 0)
{
m_reg.unregister();
m_reg = null;
}
}
}
}
}
/**
* A private inner class that implements a spell checker service;
* see SpellChecker for details of the service.
**/
private class SpellCheckerImpl implements SpellChecker
{
/**
* Implements SpellChecker.check(). Checks the
* given passage for misspelled words.
* @param passage the passage to spell check.
* @return An array of misspelled words or null if no
* words are misspelled.
**/
public String[] check(String passage)
{
// No misspelled words for an empty string.
if ((passage == null) || (passage.length() == 0))
{
return null;
}
ArrayList errorList = new ArrayList();
// Tokenize the passage using spaces and punctionation.
StringTokenizer st = new StringTokenizer(passage, " ,.!?;:");
// Lock the service list.
synchronized (m_refList)
{
// Loop through each word in the passage.
while (st.hasMoreTokens())
{
String word = st.nextToken();
boolean correct = false;
// Check each available dictionary for the current word.
for (int i = 0; (!correct) && (i < m_refList.size()); i++)
{
DictionaryService dictionary =
(DictionaryService) m_refToObjMap.get(m_refList.get(i));
if (dictionary.checkWord(word))
{
correct = true;
}
}
// If the word is not correct, then add it
// to the incorrect word list.
if (!correct)
{
errorList.add(word);
}
}
}
// Return null if no words are incorrect.
if (errorList.size() == 0)
{
return null;
}
// Return the array of incorrect words.
return (String[]) errorList.toArray(new String[errorList.size()]);
}
}
}
构建 manifest.mf:
Bundle-Description: A bundle that implements a simple spell checker service
Bundle-Vendor: Richard Hall
Bundle-Version: 1.0.0
Bundle-Activator: tutorial.example6.Activator
Export-Package: tutorial.example6.service
Import-Package: org.osgi.framework,
tutorial.example2.service
编译、打包:
D:\devInstall\apache\felix-framework-6.0.0\examples\demo06\src> javac -cp ../../demo02/target/example2.jar;../../../bin/felix.jar -encoding UTF-8 -d ../target tutorial\example6\Activator.java tutorial\example6\service\SpellChecker.java
D:\devInstall\apache\felix-framework-6.0.0\examples\demo06\src> cd ../target
D:\devInstall\apache\felix-framework-6.0.0\examples\demo06\src> cp ../src/manifest.mf ./
D:\devInstall\apache\felix-framework-6.0.0\examples\demo06\src> jar cvfm example6.jar .\manifest.mf -C . .
已添加清单
正在添加: manifest.mf(输入 = 320) (输出 = 178)(压缩了 44%)
正在添加: tutorial/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: tutorial/example6/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: tutorial/example6/Activator$1.class(输入 = 211) (输出 = 163)(压缩了 22%)
正在添加: tutorial/example6/Activator$SpellCheckerImpl.class(输入 = 1845) (输出 = 995)(压缩了 46%)
正在添加: tutorial/example6/Activator.class(输入 = 3429) (输出 = 1603)(压缩了 53%)
正在添加: tutorial/example6/service/(输入 = 0) (输出 = 0)(存储了 0%)
正在添加: tutorial/example6/service/SpellChecker.class(输入 = 189) (输出 = 147)(压缩了 22%)
安装、运行:
g! install file:./examples/demo06/target/example6.jar 00:57:20
Bundle ID: 20
g! start 20 00:57:33
org.osgi.framework.BundleException: Unable to resolve [20](R 20.0): missing requirement [[20](R 20.0)] osgi.wiring.package; (osgi.wiring.package=tutorial.example2.service) Unresolved requirements: [[[20](R 20.0)] osgi.wiring.package; (osgi.wiring.package=tutorial.example2.service)]
g! lb 00:57:38
START LEVEL 1
ID|State |Level|Name
0|Active | 0|System Bundle (6.0.0)|6.0.0
1|Active | 1|jansi (1.17.1)|1.17.1
2|Active | 1|JLine Bundle (3.7.0)|3.7.0
3|Active | 1|Apache Felix Bundle Repository (2.0.10)|2.0.10
4|Active | 1|Apache Felix Gogo Command (1.0.2)|1.0.2
5|Active | 1|Apache Felix Gogo JLine Shell (1.1.0)|1.1.0
6|Active | 1|Apache Felix Gogo Runtime (1.1.0)|1.1.0
7|Active | 1|Service listener example (1.0.0)|1.0.0
20|Installed | 1|Spell checker service (1.0.0)|1.0.0
g! install file:./examples/demo02/target/example2.jar 00:57:43
Bundle ID: 21
g! start 21 00:58:11
Ex1: Service of type tutorial.example2.service.DictionaryService registered.
g! start 20 00:58:13
Ex1: Service of type tutorial.example6.service.SpellChecker registered.
g! lb 00:58:19
START LEVEL 1
ID|State |Level|Name
0|Active | 0|System Bundle (6.0.0)|6.0.0
1|Active | 1|jansi (1.17.1)|1.17.1
2|Active | 1|JLine Bundle (3.7.0)|3.7.0
3|Active | 1|Apache Felix Bundle Repository (2.0.10)|2.0.10
4|Active | 1|Apache Felix Gogo Command (1.0.2)|1.0.2
5|Active | 1|Apache Felix Gogo JLine Shell (1.1.0)|1.1.0
6|Active | 1|Apache Felix Gogo Runtime (1.1.0)|1.1.0
7|Active | 1|Service listener example (1.0.0)|1.0.0
20|Active | 1|Spell checker service (1.0.0)|1.0.0
21|Active | 1|English dictionary (1.0.0)|1.0.0
g!
上面的例子中,我们首先将原来安装的所有 DictionaryService 卸载,然后安装了 SpellChecker,启动 SpellChecer Bundle 提示缺少可用的字典服务,这与