Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

This document explains how developers can use iPOJO extensibility mechanism. This tutorial shows two small examples: a Log Handler logging messages inside the OSGiâ?¢ OSGiâ„¢ log service and a Property Handler injecting properties values inside fields.
This document is organized as follow. First, iPOJO concepts are briefly explained. The next section explains the first step to create a handler. The two last sections describe the implementation and the usage of two example handlers.

...

iPOJO is a service component model aiming to simplify OSGiâ?¢ OSGiâ„¢ applications development. iPOJO is based on the POJO concepts. A POJO is a simple Java class without any dependency on its runtime environment. In iPOJO, POJO are encapsulated in a container managing the relation between the POJO and the external world. This container keeps separate the POJO from the external world. Moreover, this container is flexible and extensible.
Basically, iPOJO contains two main concepts: Component Type and Component Instance. A component type is a type of component. A component type defines its implementation class, its creation policy, and its container. A component instance is a configured instance of a component type. This instance is created with the component type factory. A component instance inherits of all component type characteristics but has a unique name, and owns a configuration (set of <key, value>).

...

  • void configure(InstanceManager im, Element metadata, Dictionary configuration) : this method is mandatory. Your handler will receive the instance manager on which it need to registers, the component type metadata (to parse to find your handler metadata) and the component instance configuration.
  • void start() : this method is called when the component instance management starts. Your handler needs to begin its management.
  • void stop() : this method is called when the component instance management stops. Your handler needs to end its management, and release all used services.
  • boolean isValid() : this method is called by the instance manager, when it needs to check the component instance state (VALID or INVALID). If your handler does not participate to the component instance lifecycle, you don't need to override this method. Else, you need to return if your handler is valid.
  • void stateChanged(int state) : this method is called by the instance manager each time that the instance state changes. The parameter describe the new instance state (-1 : Disposed, 0 : Stopped, 1 : Invalid, 2 : Valid).
  • void setterCallback (String fieldName, Object value) : this method is called by the instance manager, when a POJO field value changes. To be called, your handler needs to register to the field. The first argument of the method is the field name. The second argument is the new value of the field. If the field type is a primitive type, the method sends the boxing object.
  • Object getterCallback (String fieldName, Object value) : this method is called by the instance manager, when a POJO field asks for a value. To be called, your handler needs to register to the field. The first argument of the method is the field name. The second argument is the actual value of the field. This method returns the value that your handler wants to inject in the field.
  • void createInstance (Object inst) : this method is called by the instance manager, when a POJO object is created but before that anyone can use it. The argument is the created object.method is called by the instance manager, when a POJO object is created but before that anyone can use it. The argument is the created object.
  • void reconfigure(Dictionary configuration) : this method is called when the instance manager recevie a new instance configuration. This configugration can be applied whithout restarting the instance. The parameter contains the new configuration. Each handler managing the dynamic reconfiguration can, by overriden this method, apply the new configuration.
  • HandlerDescription getDescription(): this method allow an handler to participate to the instance introspection. When called, the handler needs to describe its state and returns a HandlerDescription object.

Log Handler example

This section describes how to create a simple handler. This handler logs a message in the OSGiâ?¢ OSGiâ„¢ log service when the component instance state changes. It participates to the component instance lifecycle (the handler in not valid when there is no log service available).

...

  • The bundle context (context)
  • The instance manager (manage)
  • The service reference of the actual used Log Service (ref)
  • The used log service (log)
  • The level of the log (level)

Note: Handler code is OSGiâ?¢ OSGiâ„¢ standard code. A handler cannot be a POJO.

...

Code Block
java
java
titleLogHandler.java:Configure Method
public void configure(InstanceManager im, Element metadata, Dictionary config) {
 // First parse the metadata to check if the log handler level
		
 // Get all Namespace:log element from the metadata
 Element[] log_elements = metadata.getElements("log", NAMESPACE);
		
 // if no element found, return 
 if(log_elements.length == 0) { return; } 
 else {
	// If an element match, parse the level attribute of the first element
	if(log_elements[0].containsAttribute("level")) {
		String l = log_elements[0].getAttribute("level");
		if(l.equalsIgnoreCase("info")){level=LogService.LOG_INFO; }
		else if(l.equalsIgnoreCase("error")){level=LogService.LOG_ERROR; }
       	else {level=LogService.LOG_WARNING;}
	}
			
// Register on the instance manager, to be a part of the component                  // instance container
	manager = im;
	context = manager.getContext();  // Store the bundle context
	manager.register(this);
   }
}

...

Code Block
java
java
titleLogHandler.java:Start Method
 
public void start() {
 // When starting, look for an LogService
 ref = context.getServiceReference(LogService.class.getName());
 if(ref != null) { 
   log = (LogService) context.getService(ref);
   // Log a starting message
   log.log(level,"The component instance " + manager.getInstanceName() + " is starting");
 }
// Registered a service listenner
try {
  context.addServiceListener(this,"(OBJECTCLASS="+LogService.class.getName()+")");
} catch (InvalidSyntaxException e) { e.printStackTrace(); }
}

...

Code Block
java
java
titleLogHandler.java:Stop Method
public void stop() {
 // Log the event, unget the service
 if(log != null) { log.log(level, "The component instance " + 
				manager.getInstanceName() + " is stopping"); }	
 if(ref != null) { log = null; context.ungetService(ref); } 
}

Note: do not forget to unget all used services and to release all service objects.

...

Code Block
java
java
titleLogHandler.java:stateChanged method
public void stateChanged(int state) {
 // log the state changed events
 if(log != null) {
   if(state == InstanceManager.VALID) { log.log(level, "The component 
instance " + manager.getInstanceName() + " becomes valid"); }
   if(state == InstanceManager.INVALID) { log.log(level, "The component
		instance " + manager.getInstanceName() + " becomes invalid"); }
 }
}

...

Code Block
java
java
titleLogHandler.java:serviceChanged method
public void serviceChanged(ServiceEvent event) {
  // Check if the service event does not infers with the log service
  if(ref == null && event.getType() == ServiceEvent.REGISTERED) {
    ref = event.getServiceReference();
    log = (LogService) context.getService(ref);
    // ask the component manager to check the component instance state
    manager.checkInstanceState();
 }
 if(ref != null && event.getType() == ServiceEvent.UNREGISTERING 
&& ref == event.getServiceReference()) {
  //The log service goes away
  log = null;
  context.ungetService(ref);
  ref = context.getServiceReference(LogService.class.getName());
  if(ref != null) { log = (LogService) context.getService(ref); }
  else { manager.checkInstanceState(); }
 }
}

...

Code Block
java
java
titlePropertiesHandler.java:Configure Method
public void configure(InstanceManager inst, Element meta, Dictionary conf) {
  manager = inst;
  Element[] prop_element = meta.getElements("Properties", NAMESPACE); 
  if(prop_element.length == 0) { return; }
  else {
	if(prop_element[0].containsElement("file")) { 
        file_name = prop_element[0].getAttribute("file"); 
       }
	else { return; }
	// Load the file and register the field
	File file = new File(file_name);
	try {
	  InputStream is = new FileInputStream(file);
	  props.load(is);
	} catch (FileNotFoundException e) { e.printStackTrace(); return; } 
	  catch (IOException e) { e.printStackTrace(); return ; }
	// Register to field notification
	Enumeration e = props.propertyNames();
	String[] fields = new String[props.size()];
	for(int i=0; i < fields.length; i++) {fields[i]=(String)e.nextElement();}
	manager.register(this, fields);
  }
}

...

Code Block
java
java
titlePropertiesHandler.java:Stop Method
public void stop() {
 File file = new File(file_name);
 try {
   OutputStream os = new FileOutputStream(file);
   props.store(os, "written by " + NAMESPACE);
 } catch (FileNotFoundException e) { e.printStackTrace(); } 
   catch (IOException e) { e.printStackTrace(); }
}

...

Code Block
java
java
titlePropertiesHandler.java: GetterCallback and SetterCallback methods
public void setterCallback(String fieldName, Object value) {
 // Store the new value in props (if not null) else remove the property
 if(value != null) { props.put(fieldName, value); }
 else { props.remove(fieldName); }
}
	
public Object getterCallback(String fieldName, Object value) {
  if(props.containsKey(fieldName)) { return props.get(fieldName); }
  else { return value; }
}

...