Service Management Framework is a key technology in IBM® Workplace Client Technology, Micro Edition V5.7.1, (Workplace Client Technology). The SMF development toolkit ships with the Workplace Client Technology offering to facilitate developing SMF bundles. Unfortunately, there is little documentation or tutorials which address the topic of how to develop SMF bundles in the WebSphere® Studio Device Developer (Device Developer) environment.
This article is intended as an in-depth guide to help you gain a basic understanding of the SMF programming framework and bundle development process. For this purpose, this article will give a step-by-step case study to illustrate how to develop SMF bundle with Device Developer V5.7.1. This case study will go beyond the WebSphere Studio Device Developer InfoCenter general development guide in exploring these key areas of concern:
- The code architecture of a typical SMF bundle
- Developing a bundle skeleton
- Registering a custom service with SMF Runtime
- Consumption of external services registered to SMF Runtime by other bundles
The article assumes you have a basic knowledge of SMF, with SMF runtime/server management and Device Developer experience.
In the Open Service Gateway initiative on which SMF is based, everything is represented as a bundle. For purpose of loosely-coupling and reusability, a typical SMF application is normally designed to have a toy-trick like structure. This structure may have an arbitrary number of bundles. Dependency between two different bundles generally falls into two categories, static sharing or dynamic services. In general, a typical SMF bundle that involves both of these two kinds of interactions can be divided into the following parts:
-
Bundle manifest file
A descriptor used to declare bundle native features, such as name, version, manufacture information, and the static and dynamic interaction relationship with other bundles.
-
Bundle activator implementation
Each bundle must implement the OSGi BundleActivator interface so that it can be controlled by the SMF runtime throughout its life cycle. The control events include install, update, start, and stop.
-
Custom service interface
Besides those OSGi defined services, bundle vendors can develop custom services. To do that, you should define a Java™ interface for each custom service.
-
Custom service implementation
Classes that implement the methods declared in custom service interfaces.
-
Custom Service Factory implementation
Invoke Custom Service Factory during runtime to initialize a service object. For each custom service, there should be a corresponding custom service factory class. The custom service factory class should implement the OSGi ServiceFactory interface.
-
Business logics
Business logics are referred to the remaining blackbox of a bundle other than the components above. They can be Java class files or other resource files.
In Figure 1 below, arrowed lines stand for interactions between SMF Runtime, service consumer bundle, and the service provider bundle.
Figure 1. Constructs of Bundle
In this case study, we will develop a SMF bundle named HttpLog using Device Developer V5.7.1. The HttpLog bundle provides a logging facility for upper-level bundles to record runtime log messages, which can be tracked by visiting a specified HttpServlet.
Step 1. Create a bundle skeleton
The bundle skeleton starts with a Java project, where we can do basic coding work. At first we need to create a Java project named HttpLog in Device Developer.
Modify the project build path setting to include the OSGi framework library osgi.jar and other packages that we will use in the bundle code (servlet.jar in this case).
Figure 2. Java Build Path
Step 2. Implement interface BundleActivator
In this step, we are going to create the Java class HttpLogBundleActivator, which implements the OSGi BundleActivator interface.
The interface BundleActivator declares two methods: start() and stop(). The start() method is invoked by the SMF runtime upon bundle activating. Therefore, add code to do some bundle specific initialization. The argument BundleContext is a delegation object to the runtime environment, which provides a rich set of operations that enable bundle code to invoke SMF Runtimeâs facilities, such as registering custom service and acquiring service references to external services. Record it as a member variable for later use.
//HttpLogBundleActivator.java
public class HttpLogBundleActivator implements BundleActivator {
â¦
BundleContext bc;
public void start(BundleContext context) throws Exception {
bc=context;
//to add initialization code here
}
public void stop(BundleContext context) throws Exception {
}
â¦
}
|
Step 3. Register custom service
In this step, we are going to develop one custom service named HttpLogService to implement the logging facility. There are three Java files to be created: HttpLogService.java, HttpLogServiceImpl.java, and HttpLogServiceFacotry.java.
Developer should provide an interface class and implementation class for each custom service. In this case, the service interface HttpLogService only declares one method called log(), which adds the passin message to a static message queue messageArray every time log() is invoked.
//HttpLogService.java
package httplog;
public interface HttpLogService {
void log(String message);
}
//HttpLogServiceImpl.java
package httplog;
public class HttpLogServiceImpl implements HttpLogService{
static public List messageArray = new ArrayList();
public void log(String message) {
HttpLogServiceImpl.messageArray.add(message);
}
}
|
Registration of custom services normally occurs when its hosting bundle is activated. Add the following code to the start() method of the class HttpLogBundleActivator.
//HttpLogBundleActivator.java
public class HttpLogBundleActivator implements BundleActivator {
static final String httpLogServiceName = HttpLogService.class.getName();
â¦
public void start(BundleContext context) throws Exception {
registerHttpLogService();
}
private void registerHttpLogService(){
HttpLogServiceFactory sf = new HttpLogServiceFactory();
ServiceRegistration sr=bc.registerService(httpLogServiceName,sf,null);
}
}
|
While invoking registerService(), a bundle should provide the declared custom service name, a service object that implements the OSGi ServiceFactory interface and a Dictionary object that include the properties for this service. Each ServiceFactory subclass should implement two methods: getService() and ungetService(). In our case, HttpLogService is the service to be registered and sf is of the type HttpLogServiceFactory that can generate HttpLogServiceImpl instances. For simplicity, there are no properties set for this service. The code for HttpLogServiceFactory is shown below.
//HttpLogServiceFactory.java
package httplog;
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceRegistration;
public class HttpLogServiceFactory implements ServiceFactory{
â¦
public Object getService(Bundle bun, ServiceRegistration sr) {
return new HttpLogServiceImpl();
}
public void ungetService(Bundle bun, ServiceRegistration sr, Object obj) {
}
}
|
Step 4. Consume external service
The external service consumed by the HttpLog Bundle is HttpService. Users can track the log records of HttpLog bundle by visiting an HttpServlet resided in localhost. To implement this function, HttpLog Bundle should register a servlet object with the HttpService bundle through the interface of HttpService. This task is performed when HttpLog bundle is started. Supplement the HttpLogBundleActivator class with the attachToHttp() method.
public class HttpLogBundleActivator implements BundleActivator {
â¦
static final String servletURI ="/httplog";
private void initialize(){
//Import HttpService
attachToHttp();
//register HttpLogService
registerHttpLogService();
}
private void attachToHttp(){
httpContext = new HttpContext(){
public boolean handleSecurity(HttpServletRequest request,
HttpServletResponse response)
{
return true;
}
public URL getResource(final String name)
{
return (URL) AccessController.doPrivileged(new PrivilegedAction()
{
public Object run()
{
String resource = name;
if (resource.charAt(0) != '/')
resource = "/".concat(resource); //$NON-NLS-1$
return getClass().getResource(resource);
}
});
}
public String getMimeType(String name)
{
return null;
}
};
ServiceReference httpSR = bc.getServiceReference(HttpService.class.getName());
HttpService http = (HttpService)bc.getService(httpSR);
try {
http.registerServlet(servletURI, new HttpLogServlet(), null, httpContext);
} catch (ServletException e) {
e.printStackTrace();
} catch (NamespaceException e) {
e.printStackTrace();
}
}
â¦
}
//HttpLogServlet.java
package httplog;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
public class HttpLogServlet extends HttpServlet{
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
res.setContentType("text/html; charset=UTF-8");
PrintWriter out = res.getWriter();
out.print("<html><head><title>" + "Http Log Display" + "</title></head>");
out.print("<body text=\"#000000\" bgcolor=\"#C0C0C0\"
link=\"#0000EE\" vlink=\"#551A8B\" alink=\"#FF0000\">");
List msgArray = HttpLogServiceImpl.messageArray;
int len=msgArray.size();
for (int i=0;i<len;i++){
String msg= (String)msgArray.get(i);
out.print(msg);
}
out.println("</body></html>");
}
}
|
The code above registers a custom HttpServlet object to the service HttpService during bundle initialization time. Before consuming an external service, we need to locate its instance from SMF runtime. This is done by sequentially invoking two methods:BundleContext: getServiceReference() and getService().
public ServiceReference getServiceReference(java.lang.String clazz) locates a service instance from the service registry according to the service name clazz and packages this instance in type of ServiceRefence. Note that getServiceReference() only returns one service reference to the declared service interface. Actually, there may be multiple implementations registered to one service interface at a time. To acquire all service implementations to that service, use getServiceRefrences() instead to get an array of ServiceReference objects.
public java.lang.Object getService(ServiceReference reference) returns a service implementation object. Use typecast to convert the returned object to the desired service interface type.
Step 5. Migrate to bundle format
After completing the steps above, we are now ready to package the HttpLog project into a real bundle. Prior to transformation, we need to save all modified files and compile all Java source files into classes.
Then, open File->New->SMF and choose to create a Bundle Folder. Click Next.
Figure 3. Creating a bundle folder
Choose HttpLog from available Java projects as the target bundle folder. Deselect generation options, as they are not necessary. Click Finish.
Figure 4. Choosing the bundle folder container
A folder named metainf containing a file MANIFEST.MF will be created in the project. MANIFEST.MF describes bundle metrics and its dependency with other bundles. Composing MANIFEST.MF needs to comply with the rules defined in OSGi specification. Device Developer provides a MANIFEST editor to help with composing.
Figure 5. The bundle developer screen
Several fields are mandatory to fill in in our case.
In Bundle-Name, fill in HttpLog.
In Bundle-Version, fill in 1.0.0.
In Bundle-Activator, fill in httplog.HttpLogBundleActivator
In Import Services, fill in org.osgi.service.HttpService, as this is the only service HttpLog will visit in runtime.
In Import Packages, fill in with the following packages: javax.servle, javax.servlet.http, org.osgi.framework, org.osgi.service.http. Although SMF runtime uses one JVM, it will assign different classloaders for different bundles to avoid unauthorized package sharing. Therefore, bundle should declare in the MANIFEST file which packages it will reference to maintain its own classpath.
In Export Packages, fill in with httplog.
In Export Services, fill in httplog.HttpLogService.
Figure 6. The bundle developer screen
Save the MANIFEST.MF file. The bundle is now completely ready for deploy.
Also, for reference by other bundles in later use, export the HttpLog project as a jar package httplog.jar. To perform this task, right click HttpLog project in the Project explorer view and choose Export.
Step 6. Deploy Bundle to SMF Server
Create a SMF server and start it.
Figure 7. Run window
In the Project Explorer, right click HttpLog project and choose SMF->Submit Bundleâ¦.
Figure 8. Menu dropdown
Figure 9. Target Submission window
In the Target Submission dialog, choose the SMF server just created, labeled Admin@localhost:8080/smf. Select Submit Jar and click Finish.
Open the SMF perspective, in the SMF Bundle Servers view, the HttpLog has been successfully submitted to the SMF server.
Figure 10.
Step 7. Develop testing bundle
In this step, we are going to write a bundle named HttpLogTester to invoke HttpLogService for testing purpose. This is necessary as the Http log can display content only after the HttpLogService is invoked.
This bundle is so simple that we only need to repeat step 1 and 2 to create a similar bundle skeleton. Make sure to include httplog.jar in the project build path. Implement the start() method of HttpLogTesterBundleActivator as shown below.
//HttpLogTesterBundleActivator.java
class HttpLogTesterBundleActivator implements BundleContext{
â¦
public void start(BundleContext context) throws Exception {
bc=context;
ServiceReference httpLogSR=bc.getServiceReference(httpLogServiceName);
HttpLogService httpLog =(HttpLogService)bc.getService(httpLogSR);
httpLog.log("Hello world!");
}
â¦
}
|
Repeat step 2-6 to submit the HttpLogTester to the SMF server.
Step 8. Test HttpLog in SMF runtime
We need to download and start the HttpLogTester in a SMF runtime environment. Create a SMF Runtime and start it in Device Developer. Leave all settings as default.
Figure 11. SMF Bundle Server view
Right click HttpLogTester in the SMF Bundle Server view and choose Install. The HttpLogTester Bundle along with its supporting bundles, such as HttpLog and HttpService, will be downloaded and started automatically.
Figure 12. Menu display
To track the log message, open a browser window and type http://localhost/httplog. We can see one log record as shown below.
Figure 13. Log display
Understanding the programming framework of OSGi is the basis for designing and implementing SMF-based applications. This article has introduced the major OSGi API and described how to develop a SMF bundle in Device Developer V5.7.1 from scratch.
The author would like to thank all team members involved in the GPIMM project at IBM Shanghai Globalization Lab for their help in developing this article.
| Name | Size | Download method |
|---|---|---|
| 0501huangsample.zip | 6 KB | HTTP |
Information about download methods
- Get involved in the developerWorks community by participating in
developerWorks blogs.
-
Browse for books on these and other technical topics.
Huang Chang is a software engineer in IBM Shanghai Globalization Lab (SGL). His expertise includes tools evaluation and best practices for globalization. This article is the result of his technical study in a recent Globalization Interoperability Test (GIT) project using Workplace Client Technology, Micro Edition V5.7.1. You can reach him at hchang@cn.ibm.com




