The conference runs from Monday 22nd March until the 25th. We hear that there will be plenty of copies of the book available, so be sure to pick one up while you're there!
Zesty.
7 years ago
The easy way to build service-oriented applications with OSGi
"It is only in the realm of pure science that truth is an absolute criterion. When we deal with applied science, with technology - we deal with people. And when we deal with people, considerations other than truth enter the question."
LogService and it's cousin the LogReaderService. When there are multiple registered LogService and LogReaderService pairs it can be tricky for an application to be able to present a single view of the application's logged messages.LogReaderAggregatorService. As its name implies, it aggregates each registered LogReaderService and presents a single service API with which to work with the application's entire log. The LogReaderAggregatorService is straight forward:public interface LogReaderAggregatorService extends LogReaderService {
public Enumeration/*<LogEntry>*/ getLogInOrder();
public boolean isLoggingToConsole();
public void setLogToConsole(boolean logToConsole);
} Since the interface extends the OSGi-defined LogReaderService you can use the API you're familiar with, such as getLog(), but of course what you'll get back is an Enumeration of every LogEvent for every registered LogReaderService, in reverse chronological order.LogReaderAggregatorService interfaces adds the method getLogInOrder() for accessing every logged message in chronological order, and a couple of methods for controlling whether logged messages will be echoed to the console.LogReaderAggregatorService interface is part of the required bundle org.eclipse.soda.sat.core, the implementation lives in the optional bundle org.eclipse.soda.sat.core.log.
org.eclipse.soda.sat.equinox.console.cmdprov extends the Equinox console by registering four org.eclipse.osgi.framework.console.CommandProvider services. ConfigurationAdmin service for configuration PIDs, factory PIDs and configuration properties. This command provider requires a ConfigurationAdminservice to be registered.ConfigurationAdmin.-console program argument, which is present by default for an OSGi Framework launch configuration. Typing help at the Equinox console will display the following additional command usage information:
---Bundle Dependencies---
adep- show all dependents of the specified bundle
apre- show all prerequisites of the specified bundle
dep- show dependents the specified bundle
pre- show prerequisites of the specified bundle
---Configuration Admin---
cprops [pid] - display the configuration properties
fpids [filter] - display the factory pids
pids [filter] - display the pids
---Logging---
logLevel [(debug|info|warning|error)] - query and control log level
trace [(on|off)] - query and control tracing
---Missing Imported Services of Bundles and Configurations---
ams [id] - show all missing imported services
mos [id] - show missing optional imported services
mrs [id] - show missing required imported services
FactoryUtility utility = FactoryUtility.getInstance();
BundleContext context = getBundleContext();
IProxyServiceHandler handler = new ProxyServiceHandlerAdapter() {
public Object createService() {
return new HotdogVendor();
}
};
IServiceRecord record = utility.createExportProxyServiceRecord(context, VendorService.class, handler, null);
Object service = record.getService();
boolean equal = service.equals(service);
System.out.println("service.equals(service) = " + equal);
service.equals(service) = true
equals(Object) method to compare two Proxy objects always evaluates to false, even when the receiver and the parameter are the same instance. Today's topic is how to implement the InvocationHandler interface such that the equals(Object) method is handled correctly.equals(Object) method and invoke it with an unwrapped receiver and parameter. Here's how...
public class MyInvocationHandler extends Object implements InvocationHandler {
private Object object;
public MyInvocationHandler(Object object) {
super();
this.object = object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
String name = method.getName();
if (name.equals("equals") && args.length == 1) {
MyInvocationHandler handler = toMyInvocationHandler(args [ 0 ]);
if (handler != null) {
Object[] parameters= new Object[] {
handler.object
};
result = method.invoke(object, parameters);
}
}
if (result == null) {
result = method.invoke(object, args);
}
return result;
}
private MyInvocationHandler toMyInvocationHandler(Object parameter) {
InvocationHandler handler = Proxy.getInvocationHandler(parameter);
boolean valid = handler instanceof MyInvocationHandler;
if (valid == false) return null;
MyInvocationHandler myHandler = (MyInvocationHandler) handler;
return myHandler;
}
}
InvocationHandler interface, we have the class MyInvocationHandler. The object field is used to store the object that is being proxied.equals(Object) method, and where the parameter is an instance of MyInvocationHandler, we must invoke the Method, passing as a parameter the MyInvocationHandler instance's object field.Proxy only works when the proxy is one that has an invocation handler that is an instance of MyInvocationHandler. In cases where the parameter is not an appropriate proxy, execute continues as normal in the invocation handler.
object.equal(object) aways evaluates to true, and I thought so too until a short while ago where I found that it can sometimes evaluate to false. Trust me, it can happen. Consider the following code: public interface IPerson {
//...
};
private class Person extends Object implements IPerson {
//...
};The Person class inherits its equals(Object) method from Object, the implementation of which is: public boolean equals (Object object) {
return this == object;
}So if the expression object == object always evaluates to true, and yes, it always evaluates to true, how could it be possible for the expression object.equals(object) to ever evaluate to false?Proxy should not be something you need to think about. Consider the following code that creates a proxy and then compares it with itself:final IPerson person = new Person();This code outputs the following to the console:
ClassLoader classLoader = Person.class.getClassLoader();
Class[] interfaces = {
IPerson.class
};
InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(person, args);
}
};
Object object = Proxy.newProxyInstance(classLoader, interfaces, handler);
boolean equal = object.equals(object);
System.out.println("object.equals(object): " + equal);
boolean identical = object == object;
System.out.println("object == object: " + identical);
object.equals(object): falseWhen I first saw this I could not believe my eyes, thinking that it must be a bug in either the JVM or the implementation of the
object == object: true
Proxy class, when of course it was neither. The problem lies in the anonymous inner-class implementation of the InvocationHandler interface: InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(person, args);
}
};The receiver is always a Proxy, so when we evaluate object.equals(object), execution quickly jumps to the handler's invoke method, where the expression method.invoke(person, args) is evaluated. The trick is to remember that this line of code is equivalent to:object.equals(person)This evaluates to
false because:- The
object is an instance of Proxy. - The
person is an instance of IPerson. - Both instances are distinct objects.
- The
Proxy class inherits its equals(Object) method from Object. - The expression
object == person evaluate to false.
It is unfortunate that the Proxy class does not take care of ensuring that the equals(Object) method just works as you would expect, but sadly this is not the case. If you want it to work, and you really do want it to work, your InvocationHandler must be smarter. But I'm saving that for another day.
public class Activator extends BaseBundleActivator {
private HotdogVendor vendorService;
public Activator() {
super();
vendorService= new HotdogVendor();
}
protected String[] getImportedServiceNames() {
return new String[] {
BunService.SERVICE_NAME,
WienerService.SERVICE_NAME
};
}
protected void activate() {
System.out.println("Hotdog Vendor has been activated");
BunService bunService = getBunService();
WienerService wienerService = getWienerService();
vendorService.bind(bunService, wienerService);
addExportedService(VendorService.SERVICE_NAME, vendorService, null);
}
protected void deactivate() {
vendorService.unbind();
System.out.println("Hotdog Vendor has been deactivated");
}
private BunService getBunService() {
return (BunService) getImportedService(BunService.SERVICE_NAME);
}
private WienerService getWienerService() {
return (WienerService) getImportedService(WienerService.SERVICE_NAME);
}
}
getImportedServiceNames() returns the names of the imported services. The SERVICE_NAME field is the fully qualified name of the service interface and is an SAT convention.getBunService() and getWienerService() are helper methods; another SAT convention.activate() method is a hook method that only gets called when all the bundle's imported services have been acquired. When called from the activate() method, the getBunService() and getWienerService() method are guaranteed to not return null.deactivate() method is a hook method that only gets called when the bundle loses one of its imported services.activate() and an unbind method in deactivate() is another SAT convention that simplifies the binding and unbinding of imported services. It would be equally valid to call setter methods instead.activate() and deactivate() are a pair and will get called multiple times during the lifetime of the bundle as its imported services change.CommandProvider service. SAT now includes such a bundle that adds the following commands to the console:
---SAT Bundle Dependencies---
depend <id> - show dependents the specified bundle
dependall <id> - show all dependents of the specified bundle
prereq <id> - show prerequisites of the specified bundle
prereqall <id> - show all prerequisites of the specified bundle
---SAT Logging---
loglevel {(debug|info|warning|error)} - query and control log level
trace {(on|off)} - query and control tracing
org.eclipse.soda.sat.equinox.console.cmdprov, and is optional and specific to the Equinox console."Service-Oriented Device Architecture (SODA) is an initiative to standardize and simplify the integration of devices with enterprise solutions by introducing a services-based programming model. SODA leverages existing and emerging standards from both the embedded-device and IT domains to provide well-defined interfaces for hardware devices to a service-oriented architecture (SOA)."