到目前为止,我们的基于OSGi内核的Web Application还没有任何的日志输出功能,本章将介绍如何在这个Web应用中配置和输出日志。
在前面的配置中,我们的应用中只含有commons-logging.jar,而OSGi容器之外的代码中,均是通过配置commons logging的Log对象来输出日志的,在默认的配置下,系统将采用Jdk14Logger来作为输出日志的实现,这对我们来说是远远不够的。我们下一步将配置更加常用的Log4j在作为我们的日志输出实现,通过以下几个步骤:
一、为Web Application配置Log4j:
1.在OSGi-Web项目的Java EE Module Dependencies中,增加对log4j.jar的依赖关系。
2.在WEB-INF/config目录中,增加一个log4j.properties文件,内容如下:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
### direct log messages to stdout ###
2
log4j.appender.stdout
=
org.apache.log4j.ConsoleAppender
3
log4j.appender.stdout.Target
=
System.out
4
log4j.appender.stdout.layout
=
org.apache.log4j.PatternLayout
5
log4j.appender.stdout.layout.ConversionPattern
=%
d{ABSOLUTE}
%
5p
%
c{
1
}:
%
L
-
%
m
%
n
6
7
#Default Log File Configuration For OSGi
8
log4j.appender.OSGiLog
=
org.apache.log4j.DailyRollingFileAppender
9
log4j.appender.OSGiLog.DatePattern
=
'
.
'
yyyy
-
MM
-
dd
10
log4j.appender.OSGiLog.File
=
${osgi.root}
/
logs
/
OSGi.log
11
log4j.appender.OSGiLog.layout
=
org.apache.log4j.PatternLayout
12
log4j.appender.OSGiLog.layout.ConversionPattern
=%
d [
%
t]
%-
5p
%
c
-
%
m
%
n
13
14
log4j.rootLogger
=
info, stdout
15
16
log4j.logger.org.dbstar
=
debug, OSGiLog
17
log4j.logger.org.eclipse
=
debug, OSGiLog
3.采用Spring Web的Log4j配置方式,在web.xml中增加如下配置:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
<!--
Log4j configuration
-->
2
<
context-param
>
3
<
param-name
>
webAppRootKey
</
param-name
>
4
<
param-value
>
osgi.root
</
param-value
>
5
</
context-param
>
6
<
context-param
>
7
<
param-name
>
log4jConfigLocation
</
param-name
>
8
<
param-value
>
/WEB-INF/config/log4j.properties
</
param-value
>
9
</
context-param
>
10
11
<!--
Init log4j
-->
12
<
listener
>
13
<
listener-class
>
org.springframework.web.util.Log4jConfigListener
</
listener-class
>
14
</
listener
>
4.在OSGi-Web项目的Java EE Module Dependencies中,增加spring相关jar的依赖。
经过以上4个步骤,我们在Web Application中使用commons logging输出的日志,都可以通过Log4j来显示了。但是作为OSGi容器内部来说,这还不够。OSGi规范中推荐使用 org.osgi.service.log包中的LogService和LogReaderService来管理和显示OSGi日志。为了能正常显示 OSGi容器内部的日志,我们还需要将LogService、LogReaderService和OSGi容器外部的Log4j结合起来才行,为了达到这个目的,我们还需要做以下几个步骤:
1.为OSGi容器增加一个org.osgi.service.log的实现包。在equinox-SDK-3.6M5开发包中,这个实现jar 是:org.eclipse.equinox.log_1.2.100.v20100118.jar,当然,还需要 org.eclipse.osgi.services_3.2.100.v20100108.jar,都放置到OSGi-Web工程的WEB- INT/osgi/plugins目录下面。
2.为OSGi容器增加Declarative Services支持。在equinox-SDK-3.6M5开发包中,包含了一个DS的实现:org.eclipse.equinox.ds_1.2.0.v20100125.jar,将这个jar和一个依赖的 jar:org.eclipse.equinox.util_1.0.100.v20090520-1800.jar部署到OSGi容器中,就可以使用 DS服务了。同样也放到plugins目录下面去。
3.新增一个plugin工程,名字为:org.dbstar.osgi.log,我们使用DS方式来获取服务,相关源代码如下:
OSGI-INF/log.xml
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
<?
xml version="1.0" encoding="UTF-8"
?>
2
<
scr:component
xmlns:scr
="http://www.osgi.org/xmlns/scr/v1.1.0"
enabled
="true"
name
="logListener"
xsi:schemaLocation
="http://www.osgi.org/xmlns/scr/v1.1.0 http://www.osgi.org/xmlns/scr/v1.1.0/scr.xsd"
>
3
<
implementation
class
="org.dbstar.osgi.log.LogListenerImpl"
/>
4
<
reference
cardinality
="1..1"
interface
="org.osgi.service.log.LogReaderService"
name
="LogReaderService"
policy
="static"
/>
5
</
scr:component
>
LogListenerImpl.java
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
package
org.dbstar.osgi.log;
2
3
import
org.apache.commons.logging.Log;
4
import
org.apache.commons.logging.LogFactory;
5
import
org.osgi.service.component.ComponentContext;
6
import
org.osgi.service.log.LogEntry;
7
import
org.osgi.service.log.LogListener;
8
import
org.osgi.service.log.LogReaderService;
9
import
org.osgi.service.log.LogService;
10
11
public
class
LogListenerImpl
implements
LogListener {
12
private
static
final
Log logger
=
LogFactory.getLog(LogListenerImpl.
class
);
13
14
protected
void
activate(ComponentContext context) {
15
LogReaderService service
=
(LogReaderService) context.locateService(
"
LogReaderService
"
);
16
service.addLogListener(
this
);
17
}
18
19
protected
void
deactivate(ComponentContext context) {
20
LogReaderService service
=
(LogReaderService) context.locateService(
"
LogReaderService
"
);
21
service.removeLogListener(
this
);
22
}
23
24
public
void
logged(LogEntry entry) {
25
String msg
=
getMessage(entry);
26
27
switch
(entry.getLevel()) {
28
case
LogService.LOG_DEBUG:
29
if
(logger.isDebugEnabled()) {
30
if
(entry.getException()
==
null
) {
31
logger.debug(msg);
32
}
else
{
33
logger.debug(msg, entry.getException());
34
}
35
}
36
break
;
37
case
LogService.LOG_INFO:
38
if
(logger.isInfoEnabled()) {
39
if
(entry.getException()
==
null
) {
40
logger.info(msg);
41
}
else
{
42
logger.info(msg, entry.getException());
43
}
44
}
45
break
;
46
case
LogService.LOG_WARNING:
47
if
(logger.isWarnEnabled()) {
48
if
(entry.getException()
==
null
) {
49
logger.warn(msg);
50
}
else
{
51
logger.warn(msg, entry.getException());
52
}
53
}
54
break
;
55
case
LogService.LOG_ERROR:
56
if
(logger.isErrorEnabled()) {
57
if
(entry.getException()
==
null
) {
58
logger.error(msg);
59
}
else
{
60
logger.error(msg, entry.getException());
61
}
62
}
63
break
;
64
}
65
}
66
67
private
String getMessage(LogEntry entry) {
68
StringBuilder msg
=
new
StringBuilder();
69
if
(entry.getBundle()
!=
null
) msg.append(
"
[bundle:
"
).append(entry.getBundle()).append(
"
]
"
);
70
if
(entry.getServiceReference()
!=
null
) msg.append(
"
[service:
"
).append(entry.getServiceReference())
71
.append(
"
]
"
);
72
msg.append(entry.getMessage());
73
return
msg.toString();
74
}
75
}
META-INF/MANIFEST.MF
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
Manifest-Version:
1.0
2
Bundle-ManifestVersion:
2
3
Bundle-Name: Log Bundle
4
Bundle-SymbolicName: org.dbstar.osgi.log
5
Bundle-Version:
1.0.0
6
Bundle-Vendor: dbstar
7
Bundle-RequiredExecutionEnvironment: J2SE-
1.5
8
Service-Component: OSGI-INF/log.xml
9
Import-Package: org.apache.commons.logging
;
version="1.0.4",
10
org.osgi.framework
;
version="1.3.0",
11
org.osgi.service.component
;
version="1.1.0",
12
org.osgi.service.log
;
version="1.3.0"
好了,打包成bundle jar然后也扔到plugins目录下面,然后clean一下server,启动,现在能看到多了许多日志输出,现在OSGi内部通过 LogService输出的日志也能由Log4j接管了。
最后总结一下,LogService和LogReaderService是OSGi规范中提倡的日志标准,在equinox内部实现中大量使用了这种日志,而commons logging是我们开发常规程序时所常用的日志方式。在你的bundle代码中,具体要采用哪一种日志方式,并没有强制的要求,大家可以根据各人喜好来选用。
顺便提一句,LogService有些美中不足的是,不能像commons logging那样,显示出日志具体是从哪个java类的第几行输出的,不知道各位大虾是否有人知道该如何解决呢,希望不吝赐教:)
后来发现其中在初始化时加载bundle的方式,还有一些美中不足。这种方式加载的bundle都具有相同的启动顺序,即bundle的初始化默认 start level,在之前均没有做过特别的设置,所以默认值都是1,这样会导致所有的bundle的启动顺序无法控制,在某些希望特殊bundle优先加载的场合(如日志功能,需要最先加载),我们希望能够在bundle初始化的时候就能指定特别的start level,这样所有的bundle就能按照我们预设的启动顺序来加载了。下面就是我优化过的初始化代码,能够解决启动顺序问题。
工作原理是这样的,首先,在原来存放初始化bundle的目录,也就是OSGi-Web工程的/WEB-INF/osgi/plugins目录下面再增加一个名为start的目录,在start目录下,再按照期望设置的start level来建立子目录,例如,期望设置start level为1的bundle,放到plugins/start/1目录下面;期望设置start level为2的bundle,放到plugins/start/2目录下面,以此类推。
代码方面,设置bundle的start level,需要使用StartLevel Service,可以通过下面代码获得:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
//
StartLevel Service,用于设置bundle的 startlevel
2
ServiceReference slRef
=
bundleContext.getServiceReference(StartLevel.
class
.getName());
3
StartLevel sl
=
slRef
==
null
?
null
: (StartLevel) bundleContext.getService(slRef);
然后设置initial bundle start level:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
//
设置新bundle的初始startlevel为系统配置项:org.osgi.framework.startlevel.beginning的值
2
String bsl
=
bundleContext.getProperty(
"
org.osgi.framework.startlevel.beginning
"
);
3
if
(bsl
!=
null
&&
isInteger(bsl)) sl.setInitialBundleStartLevel(Integer.parseInt(bsl));
这样所有新安装的bundle的初始化start level都将被设置为和系统配置项:org.osgi.framework.startlevel.beginning相同的值,以确保所有默认安装的 bundle都能启动。
修改osgi.properties中关于org.osgi.framework.startlevel.beginning的配置项,我改成了5:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
#Specifies the beginning start level of the framework. See Start
2
#Level Service Specification on page
235
for more information.
3
#
4
org.osgi.framework.startlevel.beginning
=
5
增加一个方法,用于安装一个目录下所有的直属bundle,并且设置start level:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
private
static
void
installBundles(BundleContext bundleContext, File bundleRoot, StartLevel sl,
int
bsl) {
2
File bundleFiles[]
=
bundleRoot.listFiles(
new
FilenameFilter() {
3
public
boolean
accept(File dir, String name) {
4
return
name.endsWith(
"
.jar
"
);
5
}
6
});
7
8
if
(bundleFiles
!=
null
&&
bundleFiles.length
>
0
) {
9
for
(File bundleFile : bundleFiles) {
10
try
{
11
Bundle bundle
=
bundleContext.installBundle(bundleFile.toURL().toExternalForm());
12
if
(sl
!=
null
&&
bsl
>
0
) sl.setBundleStartLevel(bundle, bsl);
13
if
(logger.isInfoEnabled()) logger.info(
"
Install bundle success:
"
+
bundleFile.getName());
14
}
catch
(Throwable e) {
15
if
(logger.isWarnEnabled()) logger.warn(
"
Install bundle error:
"
+
bundleFile, e);
16
}
17
}
18
}
19
}
最后,遍历start目录下的子目录来安装所有的bundle:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
//
安装bundle并设置相应的start level
2
File slRoot
=
new
File(bundleRoot,
"
start
"
);
3
if
(slRoot.isDirectory()) {
4
File slDirs[]
=
slRoot.listFiles(
new
FileFilter() {
5
public
boolean
accept(File file) {
6
return
file.isDirectory()
&&
isInteger(file.getName());
7
}
8
});
9
10
for
(File slDir : slDirs) {
11
installBundles(bundleContext, slDir, sl, Integer.parseInt(slDir.getName()));
12
}
13
}
14
15
//
安装直属目录下面的bundle
16
installBundles(bundleContext, bundleRoot, sl,
0
);
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
private
static
boolean
isInteger(String value) {
2
try
{
3
Integer.parseInt(value);
4
return
true
;
5
}
catch
(NumberFormatException e) {
6
return
false
;
7
}
8
}
最后,由于Declarative Services的存在,稍微调整了一下启动策略,所有包含Service-Component的header定义的bundle,也调用start方法来启动:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
for
(Bundle bundle : bundleContext.getBundles()) {
2
if
(bundle.getState()
==
Bundle.INSTALLED
||
bundle.getState()
==
Bundle.RESOLVED) {
3
if
(bundle.getHeaders().get(Constants.BUNDLE_ACTIVATOR)
!=
null
||
bundle.getHeaders().get(
"
Service-Component
"
)
!=
null
) {
4
try
{
5
bundle.start(Bundle.START_ACTIVATION_POLICY);
6
if
(logger.isInfoEnabled()) logger.info(
"
Start bundle:
"
+
bundle);
7
}
catch
(Throwable e) {
8
if
(logger.isWarnEnabled()) logger.warn(
"
Start bundle error:
"
+
bundle, e);
9
}
10
}
11
}
12
}
clean Server然后启动Server,我们可以看到初始化后的bundle已经被赋予了指定Start Level。
附上initFramework方法的完整代码,更多的代码请参加以前的帖子:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
//
初始化Framework环境
2
private
static
void
initFramework(Framework framework, ServletContextEvent event)
throws
IOException {
3
BundleContext bundleContext
=
framework.getBundleContext();
4
ServletContext servletContext
=
event.getServletContext();
5
6
//
将ServletContext注册为服务
7
registerContext(bundleContext, servletContext);
8
9
File file
=
bundleContext.getDataFile(
"
.init
"
);
10
if
(
!
file.isFile()) {
//
第一次初始化
11
if
(logger.isInfoEnabled()) logger.info(
"
Init Framework
"
);
12
13
String pluginLocation
=
servletContext.getInitParameter(CONTEXT_PARAM_OSGI_PLUGINS_LOCATION);
14
if
(pluginLocation
==
null
) pluginLocation
=
DEFAULT_OSGI_PLUGINS_LOCATION;
15
else
if
(
!
pluginLocation.startsWith(
"
/
"
)) pluginLocation
=
"
/
"
.concat(pluginLocation);
16
17
//
安装bundle
18
File bundleRoot
=
new
File(servletContext.getRealPath(pluginLocation));
19
if
(bundleRoot.isDirectory()) {
20
if
(logger.isInfoEnabled()) logger.info(
"
Load Framework bundles from:
"
+
pluginLocation);
21
22
//
StartLevel Service,用于设置bundle的 startlevel
23
ServiceReference slRef
=
bundleContext.getServiceReference(StartLevel.
class
.getName());
24
StartLevel sl
=
slRef
==
null
?
null
: (StartLevel) bundleContext.getService(slRef);
25
//
设置新bundle的初始startlevel为系统配置项:org.osgi.framework.startlevel.beginning的值
26
String bsl
=
bundleContext.getProperty(
"
org.osgi.framework.startlevel.beginning
"
);
27
if
(bsl
!=
null
&&
isInteger(bsl)) sl.setInitialBundleStartLevel(Integer.parseInt(bsl));
28
29
//
安装bundle并设置相应的start level
30
File slRoot
=
new
File(bundleRoot,
"
start
"
);
31
if
(slRoot.isDirectory()) {
32
File slDirs[]
=
slRoot.listFiles(
new
FileFilter() {
33
public
boolean
accept(File file) {
34
return
file.isDirectory()
&&
isInteger(file.getName());
35
}
36
});
37
38
for
(File slDir : slDirs) {
39
installBundles(bundleContext, slDir, sl, Integer.parseInt(slDir.getName()));
40
}
41
}
42
43
//
安装直属目录下面的bundle
44
installBundles(bundleContext, bundleRoot, sl,
0
);
45
46
for
(Bundle bundle : bundleContext.getBundles()) {
47
if
(bundle.getState()
==
Bundle.INSTALLED
||
bundle.getState()
==
Bundle.RESOLVED) {
48
if
(bundle.getHeaders().get(Constants.BUNDLE_ACTIVATOR)
!=
null
||
bundle.getHeaders().get(
"
Service-Component
"
)
!=
null
) {
49
try
{
50
bundle.start(Bundle.START_ACTIVATION_POLICY);
51
if
(logger.isInfoEnabled()) logger.info(
"
Start bundle:
"
+
bundle);
52
}
catch
(Throwable e) {
53
if
(logger.isWarnEnabled()) logger.warn(
"
Start bundle error:
"
+
bundle, e);
54
}
55
}
56
}
57
}
58
59
if
(slRef
!=
null
) bundleContext.ungetService(slRef);
60
}
61
62
new
FileWriter(file).close();
63
if
(logger.isInfoEnabled()) logger.info(
"
Framework inited.
"
);
64
}
65
}
Tomcat的org.apache.catalina.Context接口提供了动态管理注入到Catalina Web Container中的Web元素的API。在基于OSGi的Web Application中,可以利用这个接口来实现在OSGi容器中动态管理Web元素的目的。为了达到这个目的,我们还需要做一些额外的配置。请注意,以下方法仅适用于Tomcat,并非通用的实现,而且只针对5.5.28版和6.0.24版的Tomcat做过简单的测试。
首先我们要做的事情,就是将Tomcat的org.apache.catalina.Context实现类作为Service注入到OSGi容器中去。在 OSGi-Web工程的WebContent/META-INF目录中,增加一个context.xml文件,内容如下:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
<?
xml version="1.0" encoding="UTF-8"
?>
2
<
Context
privileged
="true"
/>
这样我们就可以使用org.apache.catalina.ContainerServlet这个接口类了,通过它可以访问Catalina的内部功能,它有Catalina被类加载器加载,而不是我们的WebApplication类加载器。它的 Setter方法在这个Servlet的新的实例被放进Service时被执行。
接下来我们写一个Servlet,这个Servlet将实现ContainerServlet接口,请注意它是怎么工作的:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
package
org.dbstar.osgi.web.launcher.tomcat;
2
3
import
java.util.Properties;
4
5
import
javax.servlet.ServletException;
6
import
javax.servlet.UnavailableException;
7
import
javax.servlet.http.HttpServlet;
8
9
import
org.apache.catalina.ContainerServlet;
10
import
org.apache.catalina.Context;
11
import
org.apache.catalina.Wrapper;
12
import
org.dbstar.osgi.web.launcher.FrameworkConfigListener;
13
import
org.osgi.framework.BundleContext;
14
import
org.osgi.framework.ServiceRegistration;
15
import
org.osgi.framework.launch.Framework;
16
17
public
final
class
TomcatContextServlet
extends
HttpServlet
implements
ContainerServlet {
18
private
static
final
long
serialVersionUID
=
-
3977062987005392657L
;
19
20
private
Wrapper wrapper;
21
private
Context context;
22
23
private
ServiceRegistration registration;
24
25
public
Wrapper getWrapper() {
26
return
wrapper;
27
}
28
29
public
void
setWrapper(Wrapper wrapper) {
30
this
.wrapper
=
wrapper;
31
if
(wrapper
==
null
) context
=
null
;
32
else
context
=
(Context) wrapper.getParent();
33
}
34
35
@Override
36
public
void
init()
throws
ServletException {
37
//
Ensure that our ContainerServlet properties have been set
38
if
((wrapper
==
null
)
||
(context
==
null
))
throw
new
UnavailableException(
"
Wrapper not set.
"
);
39
40
//
Ensure that Framework have been set
41
Framework framework
=
FrameworkConfigListener.getFramework();
42
if
(framework
==
null
)
throw
new
UnavailableException(
"
Framework not set.
"
);
43
44
//
将context注册为服务
45
registration
=
registerContext(framework.getBundleContext(), context);
46
}
47
48
private
static
ServiceRegistration registerContext(BundleContext bundleContext, Context context) {
49
Properties properties
=
new
Properties();
50
properties.setProperty(
"
DisplayName
"
, context.getDisplayName());
51
properties.setProperty(
"
ContextPath
"
, context.getPath());
52
return
bundleContext.registerService(Context.
class
.getName(), context, properties);
53
}
54
55
@Override
56
public
void
destroy() {
57
if
(registration
==
null
)
return
;
58
59
Framework framework
=
FrameworkConfigListener.getFramework();
60
if
(framework
==
null
)
return
;
61
62
if
(framework.getState()
==
Framework.ACTIVE) registration.unregister();
63
registration
=
null
;
64
}
65
}
通过ContainerServlet接口提供的setWrapper方法,我们获得了一个Wrapper实例,这个实例对应于 TomcatContextServlet部署到Tomcat中的封装类,通过其getParent方法我们就可以获得Servlet所在的 Context了。
接下来在init方法中,我们将获得的Context实例,通过Framework注册到OSGi容器中去。在destroy方法中,注销Context 的注册,这样形成了一个完整的生命周期。
然后,将这个TomcatContextServlet部署到web.xml中去:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
<!--
register a org.apache.catalina.Context to OSGi Container
-->
2
<
servlet
>
3
<
servlet-name
>
TomcatContextServlet
</
servlet-name
>
4
<
servlet-class
>
org.dbstar.osgi.web.launcher.tomcat.TomcatContextServlet
</
servlet-class
>
5
<
load-on-startup
>
1
</
load-on-startup
>
6
</
servlet
>
设置<load-on-startup>使这个Servlet在WebContainer初始化时加载,否则它将没有加载的机会,因为我们在应用中不会直接使用到这个Servlet。
最后还有一件事情不要忘记了,我们需要将org.apache.catalina及其相关的package export到OSGi容器中去,这样才能在OSGi容器中供给bundle来import。参照《打造一个基于OSGi的Web Application——为OSGi容器提供Web Application环境 》一文中提到的方式,我们将catalina.jar作为extension Fragment的方式,引入到OSGi容器中去。
Catalina的MANIFEST.MF:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
Manifest-Version:
1.0
2
Bundle-ManifestVersion:
2
3
Bundle-Name: Catalina Extension Fragment
4
Bundle-SymbolicName: org.apache.catalina_extension
;
singleton:=true
5
Bundle-Version:
5.5.28
6
Bundle-Vendor: dbstar
7
Fragment-Host: system.bundle
;
extension:=framework
8
Bundle-RequiredExecutionEnvironment: J2SE-
1.5
9
Export-Package: org.apache.catalina
,
org.apache.catalina.authenticator
,
10
org.apache.catalina.connector
,
org.apache.catalina.core
,
org.apache.cat
11
alina.deploy
,
org.apache.catalina.loader
,
org.apache.catalina.mbeans
,
or
12
g.apache.catalina.realm
,
org.apache.catalina.security
,
org.apache.catal
13
ina.session
,
org.apache.catalina.startup
,
org.apache.catalina.users
,
org
14
.apache.catalina.util
,
org.apache.catalina.valves
在接下来的章节中,我会逐一描述如何在基于Tomcat的OSGi容器中,如何实现各种Web元素的动态管理,尽请期待哦:)
最后提供几个本章提到的bundle给大家下载,大家就不用自己再起生成一个了。
org.apache.catalina_extension_5.5.28.jar