What is the best way to communicate with Bonjour? - java

There is a nice method provided by Bonjour: DNSSD.browse("_killerapp._tcp", this);. As the first argument of this method I give type of service which potentially can be available in the network, and as the second argument I give a "callback object". The considered method "browse" for the services of the indicated type (first argument).
During the browsing it can "find" and then "lose" a service. If service is found (lost) bonjour call serviceFound (serviceLost) method of the callback object. The serviceFound is called with some parameters of the found service. In more details:
serviceFound(DNSSDService browser, int flags, int ifIndex, String serviceName, String regType, String domain)
But to get the IP address and port of the service we need to do additional operation (people call it "to resolve a service"). This is logic is kind of strange to me. Why this information cannot be given by serviceFound? I mean why Bonjour cannot resolve the service automatically whenever it finds a service.
Anyway, I just accept the given logic and try to use it. From the serviceFound I call DNSSD.resolve(0, ifIndex, serviceName, regType, domain, this).
As before I give a callback object to the resolve (the last argument). Unfortunately I need to use different classes to provide the callback objects for browse and resolve. The reason for that is that browse and resolve can call a operationFailed method of the callback object and, if I use callback objects from the same class I will not know which method is calling the operationFailed (browse or resolve).
So, I create a separate class to instantiate a callback object for the resolve method. In this class I have a method called serviceResolved which is called by Bonjour with IP address and port of the resolved service:
serviceResolved(DNSSDService resolver, int flags, int ifIndex, String fullname, String hostname, int port, TXTRecord txtRecord)
I think that the IP address and port should be fields of the objects which perform browsing. So, in the serviceResolved I have IP and port and I want to set these values to the corresponding field of the instance which browse the service. But how can I do it? This instance is not given as an argument of the serviceResolved method. So, it is invisible!
Moreover, I see that serviceResolved and serviceFound take, as a first argument, DNSSDService resolver. Does anybody know what is it? May be this object can be used to set parameters of the service? I know that an object of this type is returned by the browse.

Not really an answer, but would like to point out that,
besides the Bonjour library, you may want to try JmDNS, which is a pure Java, open sourced module.

Related

Xpages: Error calling java method in a CacheBean in EL

My Xpages app has a cacheBean for application wide settings. I have a managed Bean for a PC document, which has field status of type integer.
In the cacheBean I have a method getPCStatus(Integer status) that when given the number will return the string text of the status.
On my Xpage I have a text field which I want to bind to the result of
cacheBean.getPCStatus(PCBean.status)
so it will return "In Inventory" for a 1 and something else for a 2 etc.
However, the code is throwing an error.
Here is the code:
readonly="true">
<xp:this.value><![CDATA[#{CacheBean.getPCStatus(PCModelBean.status)}]]></xp:this.value>
</xp:inputText>
The error is
Error in EL syntax, property 'value': CacheBean.getPCStatus(PCModelBean.status)
I know I read something about this long ago but cannot remember how to handle this, but cannot find it.
I was wondering if the method getPCStatus should be in the PCBean or in the cacheBean?
The version of EL used n XPages doesn't have support for calling methods with parameters. If getPCStatus() were a zero-argument method, you could call it with #{CacheBean.pCStatus}, presumably, but as it is it's the parameter that's in your way.
There are a few common workarounds: if CacheBean itself implements Map or DataObject, then EL will call the get or getValue method, respectively, with whatever you put after the "." - you could use that to sort of fake method calls.
Alternatively, you could keep CacheBean a POJO (not implementing one of those interfaces) but have the return value from getPCStatus itself be a Map or DataObject, which would take whatever value you pass in (in this case, PCModelBean.status) and do the lookup, with a binding like #{CacheBean.pCStatus[PCModelBean.status]}. DataObjects aren't too bad to write: https://frostillic.us/blog/posts/FE0AE00B7CEC4F8885257D46006CAB68
Or, as an complete alternative to all of this, if you don't need your binding to be read+write, you could use SSJS to call the method.

How to properly identify and hold client references in RMI callback?

I have a server and several "clients" (servers actually because of callbacks). A client can send a message to another only through the server. For this, the server must:
Identify the calling client.
Hold the clients' information and exported object reference so it is able to lookup the recipient.
I have read on the Remote Session pattern (1, 2, 3) and here and here, but I couldn't find the answer I was looking for.
For (1), I see the following options:
The client sends its exported object reference during the call to the server.
The client sends some identification information during the call to the server.
The client is identified with getClientHost.
The recipient must be sent as some identification information since clients do not hold a reference to each other.
public interface RemoteClient extends Remote {
void message(String sender, String message);
}
public interface RemoteServer extends Remote {
void relayMessage(String recipient, RemoteClient sender, String msg);
// or some identifier? // or string/identifier?
}
public class RemoteServerImpl extends UnicastRemoteObject implements RemoteServer {
void relayMessage(String recipient, RemoteClient sender, String msg) {
RemoteClient recp = lookup(recipient); // See point 2 below
String sndr = getRepresentation(sender); // See below...
recp.message(sndr, msg);
// OR using
String sndr = getRepresentation(getClientHost());
// Then sender parameter is not needed
}
}
I'm pretty sure getClientHost is not a reliable way of identifying the caller because it can disconnect and reconnect with a different IP, and I'm not sure if there are 2 computer in the same LAN that this method will be able to distinguish between them.
For (2), the options I see are:
Keep a Map of the identification information and the clients' exported objects (as mentioned, but not recommended, in one of the above answers).
Keep a Set of client information objects where these objects hold the remote object reference and whatever relevant information.
These are updated during login (registration) and logout.
Then lookup takes the information and returns the remote object reference and getRepresentation is similar to a reverse lookup.
My problem is not to make it work (it's working), it's to make it work correctly. Is there any advantage or preferred way from the above or otherwise?
You don't appear to have understood the remote session pattern at all. The session object the client is calling remote methods on is unique to the client, so there is no necessity for it to further identify itself during subsequent calls to the session. Whatever information the client sent to the login object to obtain the session can be stored in the session object, or the server can assign a unique client ID itself. The session object should also contain the callback of course: it's the only sensible place to put it.

Google Cloud Endpoints call one endpoint from another

Let's say I have the following Google Cloud Endpoints:
#ApiMethod(name = "account.insert")
public Account insertAccount(Account account, #Named("userId") Long userId)
#ApiMethod(name = "user.get")
public User getUser(#Named("id") Long id)
Let's assume Account has a reference to User, which shall be created when the account is inserted. So what I need to do is look up the user by userId first to make sure it exists, then set the reference in Account.
To avoid redundancy, I decided it would be good to call getUser(userId) as this functionality exists as another endpoint.
This would work fine as long as both methods/endpoints are in the same class/file. As soon as I cross the class boundaries, I receive the following message:
"non-static method (...) cannot be referenced from a static content"
First of all, I don't understand why the content is static if it isn't marked as static in the method signature, but maybe the #ApiMethod annotation does its job here, because it is understandable that the API is exposed as a static method.
Second, I would probably be able to get around this by using a delegate function, but then I would like to know if it is considered good practice to call into one of my own endpoints from another endpoint.
Let me know what you think, please.

Java: Accessing a interface function from a class which implements the interface

Background:
I have a list of classes (comm objects), which may or may not increase. They all implement the same method in an interface Comms:
public int send(Socket socket, byte[] message);
I get a list of these comm classes by specifying the package name in the method's packageName parameter (excluding the package name itself internally in the function and doing some filtering to get just the names package comm):
public static Class[] getClasses(String packageName); (modified it a bit from the link below)
http://www.dzone.com/snippets/get-all-classes-within-package
Then I have several plugins which are configurable to use one of the comm objects as base communication.
Comm objects:
serial
client
server
etc.
Plugins:
plugin1
plugin2
etc.
The manager class will receive a request for sending a control packet from a plugin, and the manager will just queue the requests and call the send function for each request on a
Question:
How do I access the method send(Socket socket, byte[] message); within manager or the plugin itself?
This involves creating a generic class object which may call send, which is cast from one of the comm classes, depending on the plugin configuration, from the string name of the comm object.
The configuration of which comm class is used for each plugin is stored within a database. Converting from string to a Class object works well. I just need to find a way to call the send function which resides in the interface Comm which is implemented by all the comm classes. This has to be generic. More comm classes may be added.
Give the manager a reference type Comm interface and call its send method.
When you instantiate the manager, inject it with the implementation that you wish.
It sounds like you already have the virtual constructor/factory pattern down for instantiating each type of Comm implementation.
This is a common pattern for all dependency injection engines (e.g. Spring, Guice, etc.)

java.lang:type=Runtime is not an instance of interface java.lang.management.RuntimeMXBean

final RuntimeMXBean remoteRuntime =
ManagementFactory.newPlatformMXBeanProxy(
serverConnection,
ManagementFactory.RUNTIME_MXBEAN_NAME,
RuntimeMXBean.class);
Where the serverConnection is just basically connecting to a jmx server.
What basically is going on is, this piece of code works fine. Let me explain:
The first call of this piece of code calls to server A, I then scrape some data in it and store it into an xml file. Using this information, start up a new server B.
Then, in wanting to verify B, I want to scrape B to compare the metadata. But when I run it I get the exception
java.lang.IllegalArgumentException: java.lang:type=Runtime is not an instance of interface java.lang.management.RuntimeMXBean
at java.lang.management.ManagementFactory.newPlatformMXBeanProxy(ManagementFactory.java:617
)
But, not sure what changes here since the parameters that are giving me problems are managed by the ManagementFactory class I don't have control over.
The problem was with my own MBeanServer implementation.
I had it returning false for the isInstanceOf() method if the passed in objectName returned a null Object. It turns out that this happened at all RunTime Classes so after reading http://tim.oreilly.com/pub/a/onjava/2005/01/26/classloading.html under the Class Loader section, I went with the fact that my ClassLoaderImplementation was incorrect and was loading these incorrectly.
Work around was just to return true in isInstanceOf() for these RunTime classes.

Categories