Alessandro Alinone
With Lightstreamer Server v.3.5, parallel initialization of the Adapters was introduced. This means that any previously suggested mechanisms for letting the Adapters find each other must be made more robust.
In the distribution of Lightstreamer 3.5+ there are several examples of Data and Metadata Adapter finding each other in a robust way. An example is reported below:
adapters.xml:
[SYNTAX="XML"]<adapters_conf id="CHAT">
<metadata_provider>
<adapter_class>chat_demo.adapters.ChatMetadataAdapter</adapter_class>
<!-- Mandatory for ChatMetadataAdapter.
Identification name assigned to the instance of
ChatDataAdapter included in this Adapter Set (see below).
This allows the ChatMetadataAdapter to recognize the
related instance of ChatDataAdapter, in order to forward
messages received from the clients. -->
<param name="match_id">chat1</param>
</metadata_provider>
<data_provider name="CHAT_ROOM">
<adapter_class>chat_demo.adapters.ChatDataAdapter</adapter_class>
<!-- Mandatory for ChatDataAdapter.
Identification name to be assigned to this adapter instance.
This allows the ChatMetadataAdapter to recognize the
related instance of ChatDataAdapter, in order to send messages
received from the clients.
If multiple Adapter Sets include a ChatDataAdapter,
different identification names should be assigned. -->
<param name="match_id">chat1</param>
</data_provider>
</adapters_conf>[/SYNTAX]
ChatDataAdapter.java:
[SYNTAX="JAVA"]package chat_demo.adapters;
...
public class ChatDataAdapter implements SmartDataProvider {
/**
* A static map, to be used by the Metadata Adapter to find the data
* adapter instance; this allows the Metadata Adapter to forward client
* messages to the adapter.
* The map allows multiple instances of this Data Adapter to be included
* in different Adapter Sets. The "match_id" configuration argument
* must be used to uniquely indentify each instance and the same name
* must be supplied for the Data and Metadata Adapter configuration
* in the same Adapter Set.
*/
public static final ConcurrentHashMap<String, ChatDataAdapter> feedMap =
new ConcurrentHashMap<String, ChatDataAdapter>();
...
public void init(Map params, File arg1) throws DataProviderException {
// Read the match_id parameter, to uniquely identify the instance
String adapter_id = (String) params.get("match_id");
if (adapter_id == null) {
logger.error("match_id for data adapter is missing");
throw new DataProviderException(
"match_id for data adapter is missing");
}
// Put a reference to this instance on a static map
// to be read by the Metadata Adapter
feedMap.put(adapter_id, this);
// Adapter ready
logger.info("ChatDataAdapter ready");
}
...
}[/SYNTAX]
ChatMetadataAdapter.java:
[SYNTAX="JAVA"]package chat_demo.adapters;
...
public class ChatMetadataAdapter extends LiteralBasedProvider {
/**
* The associated feed to which messages will be forwarded;
* it is the Data Adapter itself.
*/
private volatile ChatDataAdapter chatFeed;
/**
* Unique identification of the related Chat Data Adapter instance;
* see feedMap on the ChatDataAdapter.
*/
private String matchId;
...
public void init(Map params, File configDir) throws MetadataProviderException {
//Call super's init method to handle basic Metadata Adapter features
super.init(params,configDir);
//Read the match_id parameter from adapter configuration;
this.matchId = (String) params.get("match_id");
if (this.matchId == null) {
logger.error("match_id for metadata adapter is missing");
throw new MetadataProviderException("match_id for metadata adapter is missing");
}
/*
* Note: the ChatDataAdapter instance cannot be looked for
* here to initialize the "chatFeed" variable, because the Chat
* Data Adapter may not be loaded and initialized at this moment.
* We need to wait until the first "sendMessage" occurrence;
* then we can store the reference for later use.
*/
logger.info("ChatMetadataAdapter ready");
}
/**
* Triggered by a client "sendMessage" call.
* The message encodes a chat message from the client.
*/
public void notifyUserMessage(String user, String session, String message)
throws NotificationException, CreditsException {
...
this.loadChatFeed();
...
}
...
private void loadChatFeed() throws CreditsException {
if (this.chatFeed == null) {
try {
// Get the ChatDataAdapter instance to bind it with this
// Metadata Adapter and send chat messages through it
this.chatFeed = ChatDataAdapter.feedMap.get(this.matchId);
} catch(Throwable t) {
// It can happen if the Chat Data Adapter jar was not even
// included in the Adapter Set lib directory (the Chat
// Data Adapter could not be included in the Adapter Set as well)
logger.error("ChatDataAdapter class was not loaded: " + t);
throw new CreditsException(0, "No chat feed available", "No chat feed available");
}
if (this.chatFeed == null) {
//The feed is not yet available on the static map, maybe there is an
//error on the configuration of the match_id parameter
logger.error("ChatDataAdapter not found");
throw new CreditsException(0, "No chat feed available", "No chat feed available");
}
}
}
...
}[/SYNTAX]
Basically, the actual communication between the Adapters should begin only after all the init() methods have completed. In the example above, this is accomplished in the Metadata Adapter by looking for the Data Adapter on the notifyUserMessage() call, which is called after all the init() methods for all Adapters have completed.
More in general, the following rule applies: Any method of any Adapter, except for init() and setListener(), is guaranteed to be called after the init() methods of all the Adapters() have finished their execution.
Mone
Hi,
can you please explain your situation?
The above discussion does not involve java applets at all.
Also, the Microsoft Java Virtual Machine was dismissed a long time ago, and none of our software still supports it.
You should use the Java Virtual Machine from oracle (or any other java virtual machine that supports at least java 5)