Zesty.
6 years ago
The easy way to build service-oriented applications with OSGi
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 ConfigurationAdmin
service 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 {The
//...
};
private class Person extends Object implements IPerson {
//...
};
Person
class inherits its equals(Object)
method from Object
, the implementation of which is:public boolean equals (Object object) {So if the expression
return this == object;
}
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() {The receiver is always a
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(person, args);
}
};
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.