本文介绍如何在Equinox中集成Tuscany,Tuscany容器作为OSGI环境中的一个Bundle存在。同时一个Contribution也对应为一个Bundle,此种方式使Tuscany的Contribution具有了热部署和动态修改替换的能力。这也是Tuscany邮件组中目前正在讨论的问题。
修改Tuscany:
a)
DefaultSCADomain
是在构造方法中加载
Contribution
的资源。修改
OsgiSCADomain
,添加
initContribution(Bundle bundle)
方法。代码片断如下:
ContributionService contributionService =
runtime
.getContributionService();
URL contributionURL;
try
{
contributionURL = getContributionLocation(bundle);
if
(contributionURL !=
null
) {
// Make sure the URL is correctly encoded (for example, escape the space characters)
contributionURL = contributionURL.toURI().toURL();
}
}
catch
(Exception e) {
throw
new
ServiceRuntimeException(e);
}
|
以上代码,获取Bundle的META-INF目录下sca-contribution.xml的URL,并通过
ContributionService
的
contribute
加载
sca-contribution.xml
及其他资源文件。在实验代码中仅考虑
.composite
文件。
b) 替换org.apache.tuscany.sca.host.embedded.
SCADomain扩展点实现为
org.apache.tuscany.sca.host.embedded.impl.OsgiSCADomain
。
2.
另一个主要问题是要考虑
ClassLoader
的问题。在
OSGI
中,不同的
Contribution
使用不同的
ClassLoader
。因此在
org.eclipse.equinox.tuscany
插件中对构件进行装配时,无法加载构件描述文件的的类。
a)
新建
BundleProxyClassLoader
,
Bundle
默认不对外提供
ClassLoader
,因此创建一个代理
ProxyClassLoader
。
BundleProxyClassLoader
的代码参见:
http://wiki.eclipse.org/index.php/BundleProxyClassLoader_recip
3.
BundleContext
在
Tuscany
中传递的问题。如果要将
BundleContext
直接在
Tuscany
中传递,需要修改大量已有代码,代价较大。采用折中方法。修改
Contribution
接口,添加
setBundle
和
getBundle
方法。
Bundle getBundle();
void
setBundle(Bundle bundle);
|
4.
修改
ContributionServiceImpl,
a)
添加
addContribution
方法,在此方法中将
Bundle
设置给
Contribution
。
b)
添加
readContributionMetadata
方法
。在此方法中将
BundleProxyClassLoader
传给
ContributionMetadataDocumentProcessor
,用户加载
sca-contribution.xml
文件。
private
Contribution readContributionMetadata(Bundle bundle)
throws
ContributionException{
Contribution contributionMetadata =
null
;
ClassLoader cl =
new
BundleProxyClassLoader(bundle);
ContributionMetadataDocumentProcessor metadataDocumentProcessor =
new
ContributionMetadataDocumentProcessor(cl, staxProcessor, assemblyFactory, contributionFactory,
xmlFactory);
contributionMetadata = contributionFactory.createContribution();
try
{
metadataDocumentProcessor.read(contributionMetadata);
}
catch
(XMLStreamException e) {
throw
new
InvalidContributionMetadataException(
"Invalid contribution metadata for contribution."
);
}
return
contributionMetadata;
}
|
5.
修改
ClassReferenceModelResolver
,使用
Contribution
中
Bundle
的
ClassLoader
来加载
Java Class
。
public
ClassReferenceModelResolver(Contribution contribution, ModelFactoryExtensionPoint modelFactories) {
this
.
contribution
= contribution;
//
FIXME
The classloader should be passed in
// this.classLoader = new WeakReference
(Thread.currentThread().getContextClassLoader());
this
.
classLoader
=
new
WeakReference
(
new
BundleProxyClassLoader(contribution.getBundle()));
try
{
Class osgiResolverClass =
Class.forName(
"org.apache.tuscany.sca.contribution.osgi.impl.OSGiClassReferenceModelResolver"
);
if
(osgiResolverClass !=
null
) {
Constructor constructor =
osgiResolverClass.getConstructor(Contribution.
class
, ModelFactoryExtensionPoint.
class
);
this
.
osgiResolver
= (ModelResolver)constructor.newInstance(contribution, modelFactories);
}
}
catch
(Exception e) {
}
}
|
创建
org.apache.tuscany
和
org.eclipse.equinox.tuscany
两个插件
org.apache.tuscany
插件包含了
Tuscany
运行时刻类库文件。
SCAActivator
代码如下:
public
class
SCAActivator
implements
BundleActivator, BundleTrackerCustomizer, SynchronousBundleListener {
private
BundleTracker
bundleTracker
;
public
SCAActivator() {
activator
=
this
;
}
return
activator
;
}
/*
* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
public
void
start(BundleContext bundleContext)
throws
Exception {
scaDomain
= SCADomain.newInstance();
bundleTracker
=
new
BundleTracker(bundleContext, Bundle.
ACTIVE
,
this
);
bundleContext.addBundleListener(
this
);
//track UNRESOLVED events
bundleTracker
.open();
}
/*
* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public
void
stop(BundleContext context)
throws
Exception {
scaDomain
.close();
}
public
void
bundleChanged(BundleEvent event) {
if
(event.getType() == BundleEvent.
UNRESOLVED
) {
//
TODO
}
else
if
(event.getType() == BundleEvent.
RESOLVED
) {
//
TODO
}
}
public
Object addingBundle(Bundle bundle) {
domain.initContribution(bundle);
}
return
null
;
}
public
void
modifiedBundle(Bundle bundle, Object object) {
//
TODO
}
public
void
removedBundle(Bundle bundle, Object object) {
//
TODO
}
public
SCADomain getScaDomain() {
return
scaDomain
;
}
}
|
运行时刻调用
在
Servlet
中可以使用如下方式调用:
public
void
doGet(HttpServletRequest request, HttpServletResponse response)
throws
IOException{
response.setContentType(
"text/html"
);
ServletOutputStream output=response.getOutputStream();
CalculatorService calculatorService =
scaDomain.getService(CalculatorService.
class
,
"CalculatorServiceComponent"
);
// Calculate
output.println(
"3 + 2="
+ calculatorService.add(3, 2) +
"
" );
output.println(
"3 - 2="
+ calculatorService.subtract(3, 2) +
"
" );
output.println(
"3 * 2="
+ calculatorService.multiply(3, 2) +
"
" );
output.println(
"3 / 2="
+ calculatorService.divide(3, 2) +
"
" );
}
|