Load all friends using google play services - java

http://discuss.cocos2d-x.org/t/google-play-game-services/7190/10 here there is a code that is for loading friends. This code is old and I have updated it to new version:
public static void loadFriends(JSONObject parameters) {
if (mFriends.size() > 0) {
mFriends.clear();
}
((AppActivity)mContext).runOnUiThread(new Runnable() {
public void run() {
Games.Players.loadInvitablePlayers(((AppActivity)mContext).getApiClient(), FRIENDS_PER_PAGE, false).setResultCallback(new ResultCallback<LoadPlayersResult>(){
#Override
public void onResult(LoadPlayersResult result) {
Log.w("GOOGLE SERVICES ****** ", "onResult");
PlayerBuffer playerBuffer = result.getPlayers();
for (Player player : playerBuffer) {
mFriends.add(player);
Log.i("GOOGLE SERVICES ---- ", String.format("Found player with id [%s] and display name [%s]", player.getPlayerId(), player.getDisplayName()));
}
if (playerBuffer.getCount() == FRIENDS_PER_PAGE) {
Log.w("GOOGLE SERVICES +++=== ", "loadMoreInvitablePlayers");
Games.Players.loadMoreInvitablePlayers(((AppActivity)mContext).getApiClient(), FRIENDS_PER_PAGE);
} else {
// call out and return all the friends
Log.w("GOOGLE SERVICES======== ", "call out and return all the friends");
for (Player friend : mFriends) {
Log.i("GOOGLE SERVICES", String.format("Found player with id [%s] and display name [%s]", friend.getPlayerId(), friend.getDisplayName()));
}
}
} // onResult
}); // loadInvitablePlayers
} // run
}); // runOnUiThread
}
But this works strangely. It loads from the first call 20 players, whereas the page size is 10 and considers that all the players are loaded. But I actually have more friends. How to load all my friends?

According to documentation, that behavior is normal:
"The number of entries to request for this initial page. Note that if cached data already exists, the returned buffer may contain more than this size, but it is guaranteed to contain at least this many if the collection contains enough records. This must be a value between 1 and 25."

Related

Unity+PlayFab c# sequential execution

Please advise on C# syntax, I am doing Rest API Call toward PlayFab to get a player profile and then get assign the player display name to a local public variable, BUT during execution the sequence of function I found that they are not sequential at all. I don't understand why, as in python or java, all function is sequential and they will be executed after another function has completed.
By the logic, it should execute start function with OnLoginWithGoogleAccountPlayFab which will call GetPlayerProfile fetch the player name and assign on a public string PlayerDisplayName, then call ChangeSceneOnNewPlayer which will check for name if it is null.
But it executes this way enter image description here
public PlayerDisplayName;
void Start(){
OnLoginWithGoogleAccountPlayFab();
}
public void OnLoginWithGoogleAccountPlayFab() {
PlayFabClientAPI.LoginWithGoogleAccount(new LoginWithGoogleAccountRequest()
{
TitleId = PlayFabSettings.TitleId,
ServerAuthCode = AuthCode,
CreateAccount = true
}, (result) =>
{
PlayFabId = result.PlayFabId;
SessionTicket = result.SessionTicket;
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- --------------------- GET PROFILE 1");
GetPlayerProfile();
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- ---------------------NAME 1 ");
ChangeSceneOnNewPlayer();
}, OnPlayFabError);
}
public void GetPlayerProfile() {
PlayFabClientAPI.GetPlayerProfile(new GetPlayerProfileRequest()
{
PlayFabId = PlayFabId,
ProfileConstraints = new PlayerProfileViewConstraints()
{
ShowDisplayName = true,
}
}, (result) =>
{
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- ---------------------PROFILE 2");
Debug.Log("The player's DisplayName profile data is: " + result.PlayerProfile.DisplayName);
PlayerDisplayName = result.PlayerProfile.DisplayName;
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- ---------------------PROFILE 3");
}, OnPlayFabError);
}
public void ChangeSceneOnNewPlayer() {
Debug.Log("Player Info");
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- ---------------------NAME 2 ");
if (PlayerDisplayName == null) {
Debug.Log("Player Info is NULL " + PlayerDisplayName);
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- ---------------------NAME 3 ");
SceneManager.LoadSceneAsync("New_Player", LoadSceneMode.Single);
} else {
Debug.Log("Player Info NOT null " + PlayerDisplayName);
Debug.LogWarning("waaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrr- ---------------------NAME 3 ");
SceneManager.LoadSceneAsync("City", LoadSceneMode.Single);
}
}
Your methods are being executed sequentially, but the results you get back are returned asynchronously. This introduces race conditions to your code and is the reason you see the ChangeSceneOnNewPlayer method being executed before you have received the player profile.
Let's break down what's happening in the following lines (debugging removed for clarity):
// Both these lines execute synchronously.
PlayFabId = result.PlayFabId;
SessionTicket = result.SessionTicket;
// Here you're invoking a synchronous method, but inside the method
// an asynchronous call is made to PlayFab, and the result will not be immediately
// returned.
GetPlayerProfile();
// Then you immediately call this method, but you haven't waited for the result from
// PlayFab before you make this call.
ChangeSceneOnNewPlayer();
What you want is something more like this:
public PlayerDisplayName;
void Start()
{
OnLoginWithGoogleAccountPlayFab();
}
public void OnLoginWithGoogleAccountPlayFab()
{
PlayFabClientAPI.LoginWithGoogleAccount(new LoginWithGoogleAccountRequest()
{
TitleId = PlayFabSettings.TitleId,
ServerAuthCode = AuthCode,
CreateAccount = true
}, (result) =>
{
PlayFabId = result.PlayFabId;
SessionTicket = result.SessionTicket;
// Get the profile, and specify a callback for when the result is returned
// from PlayFab.
GetPlayerProfile(OnGetPlayerProfile);
}, OnPlayFabError);
}
public void GetPlayerProfile(Action<PlayerDisplayName> onGetPlayerDisplayName)
{
PlayFabClientAPI.GetPlayerProfile(new GetPlayerProfileRequest()
{
PlayFabId = PlayFabId,
ProfileConstraints = new PlayerProfileViewConstraints()
{
ShowDisplayName = true,
}
}, onGetPlayerDisplayName, OnPlayFabError);
}
// This method is used as a callback to your GetPlayerProfile function and is used
// to process the information.
public void OnGetPlayerProfile(PlayerDisplayName playerDisplayName)
{
PlayerDisplayName = playerDisplayName;
if (PlayerDisplayName == null)
{
SceneManager.LoadSceneAsync("New_Player", LoadSceneMode.Single);
}
else
{
SceneManager.LoadSceneAsync("City", LoadSceneMode.Single);
}
}
This is a standard pattern when using any RESTful API calls.

How to send custom graph data to MCStats every hour?

I have been working on a plugin and have gotten some really interesting data with it, I am trying to add a custom graph and have succeeded on getting the graph to appear with the name I set in code on MCStats.
My plugin is here and recreates the Dense Ores Mod.
I would like to send block mined data on an hourly basis. This is what I have in my onEnable so far:
try {
Metrics metrics = new Metrics(this);
Graph blocksMinedGraph = metrics.createGraph("Extra items from blocks");
blocksMinedGraph.addPlotter(new Metrics.Plotter("Coal Ore") {
#Override
public int getValue() {
return coalMined;
}
});
blocksMinedGraph.addPlotter(new Metrics.Plotter("Iron Ore") {
#Override
public int getValue() {
return ironMined;
}
});
metrics.start();
} catch (IOException e) {
getLogger().info(ANSI_RED + "Metrics have been unable to load for: DenseOres" + ANSI_RESET);
}
This has successfully created a new graph on my MCStats page called 'Extra items from blocks' although I have been unable to populate it thus far. I have tried but cannot work out how to send the data.
Connected to this question, when sending the data, will I have to keep a count of the values in a file somewhere so they persist between reloads and server restarts?
I appear to have solved it by placing the blocksMinedGraph.addPlotter(...) parts in an async repeating task.
Here is the code with the repeating task in place, the graphs on MCStats take forever to update though.
try {
Metrics metrics = new Metrics(this);
if (!metrics.isOptOut()) {
final Graph blocksMinedGraph = metrics.createGraph("Extra items from blocks (Since v2.3)");
Bukkit.getScheduler().runTaskTimerAsynchronously(this, new Runnable() {
public void run() {
getLogger().info("Graph data sent");
blocksMinedGraph.addPlotter(new Metrics.Plotter("Coal Ore") {
#Override
public int getValue() {
return coalMined;
}
});
blocksMinedGraph.addPlotter(new Metrics.Plotter("Iron Ore") {
#Override
public int getValue() {
return ironMined;
}
});
}
}, DELAY, INCREMENT);
getLogger().info("Metrics started");
metrics.start();
}
} catch (IOException e) {
getLogger().info(ANSI_RED + "Metrics have been unable to load for: DenseOres" + ANSI_RESET);
}

How to get the user's current speed using Google Fit's API?

Working with the Google Fit API at the moment and having a bit of trouble with the Sensors API. I'm trying to get user's current speed for my app's workouts but the documentation is a bit confusing.
In this code snippet is an example from Google's info page:
Fitness.SensorsApi.add(
mClient,
new SensorRequest.Builder()
// Optional but recommended for custom data sets.
.setDataType(DataType.TYPE_SPEED)// Can't be omitted.
.setSamplingRate(1, TimeUnit.SECONDS).setAccuracyMode(SensorRequest.ACCURACY_MODE_HIGH)
.build(), mListener3)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Listener registered!");
} else {
Log.i(TAG, "Listener not registered.");
}
}
});
//Adding a Listener
mListener3 = new OnDataPointListener() {
#Override
public void onDataPoint(DataPoint dataPoint) {
final float speed = dataPoint.getValue(Field.FIELD_SPEED).asFloat();
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i(TAG, "In Speed" + speed );
speedTxtView.setText("" + speed );
}
});
}
Currently, I am getting all other datatype values like distance, heart rate ,step count and current activity but unable to get user's current speed.
Is i am doing correctly?
You could try the basichistorysessions sample from Google Fit Github repository.
sample code:
// Build a session read request
SessionReadRequest readRequest = new SessionReadRequest.Builder()
.setTimeInterval(startTime, endTime, TimeUnit.MILLISECONDS)
.read(DataType.TYPE_SPEED)
.setSessionName(SAMPLE_SESSION_NAME)
.build();
// Invoke the Sessions API to fetch the session with the query and wait for the result
// of the read request.
SessionReadResult sessionReadResult =
Fitness.SessionsApi.readSession(mClient, readRequest)
.await(1, TimeUnit.MINUTES);
// Get a list of the sessions that match the criteria to check the result.
Log.i(TAG, "Session read was successful. Number of returned sessions is: "
+ sessionReadResult.getSessions().size());
for (Session session : sessionReadResult.getSessions()) {
// Process the session
dumpSession(session);
// Process the data sets for this session
List<DataSet> dataSets = sessionReadResult.getDataSet(session);
for (DataSet dataSet : dataSets) {
dumpDataSet(dataSet);
}
}
You can refer to this reading fitness data using sessions section for more information.
To get the speed, dataSourceType should be derived. The following works for me
Fitness.SensorsApi.findDataSources(mClient, new DataSourcesRequest.Builder()
.setDataTypes(DataType.TYPE_SPEED)
.setDataSourceTypes(DataSource.TYPE_DERIVED)
.build())
.setResultCallback(new ResultCallback<DataSourcesResult>() {
#Override
public void onResult(DataSourcesResult dataSourcesResult) {
Log.i(TAG, "Result: " + dataSourcesResult.getStatus().toString());
for (DataSource dataSource : dataSourcesResult.getDataSources()) {
Log.i(TAG, "Data source found: " + dataSource.toString());
}
}
});

MultipleChatUser XMPP asmack join

I am new to this OpenFire and asmack, i want the user to have a functionality of Multi Users Chatting so i searched around and i found MUC i have implemented this for creating a room and sending invitation to other users these works, other user receives the invitation but the other user is not able to join the room.
I am doing this on other user invitation receiving
Here connection is the connection of this user and room is the room name that we getting in invitation.
MultiUserChat muc3 = new MultiUserChat(connection,room);
muc3.join("testbot3");
testbot3 is just some random name.
But this throws 404 error.
Do i need to join the user before sending the invitation i.e if A user sending invitation to B , before invitation sent do A needs to join these users by default to room and then it depends on B to decline or just keep quite.
What i am doing is B receives invitation from A in that InvitationListner of B i am trying to join with the above code.
I have been trying for long now i am not sure what is going wrong, some one can give a sample code of how to do this it would be great help for me.
Thanks
Here is more information on my issue
As i go and check on Openfire i can see the room created by the user and he has been added himself as an owner so i dont think so it would be an issue with room getting created.
May be this can be an issue with room getting locked, as i have read through the room is locked when the room is not completely created , i guess this is an issue with form filling when we create the room, i am not filling in the password in the form can this be an issue ?
Please see the following code below inside the handler i am calling a method "checkInvitation" which does the same as above code posted still i get 404. Can you please tell me what i wrong in my code.
Do the nickname that needs to be added can be anything or it needs to something user specific ?
public void createChatroom(){
MultiUserChat muc = null;
try {
muc = new MultiUserChat(connection, "myroom#conference.localhost");
muc.create("testbot");
// Get the the room's configuration form
Form form = muc.getConfigurationForm();
// Create a new form to submit based on the original form
Form submitForm = form.createAnswerForm();
// Add default answers to the form to submit
for (Iterator fields = form.getFields(); fields.hasNext();) {
FormField field = (FormField) fields.next();
if (!FormField.TYPE_HIDDEN.equals(field.getType()) && field.getVariable() != null) {
// Sets the default value as the answer
submitForm.setDefaultAnswer(field.getVariable());
}
}
// Sets the new owner of the room
List owners = new ArrayList();
owners.add("admin#localhost");
submitForm.setAnswer("muc#roomconfig_roomowners", owners);
// Send the completed form (with default values) to the server to configure the room
muc.sendConfigurationForm(submitForm);
muc.join("d");
muc.invite("b#localhost", "Meet me in this excellent room");
muc.addInvitationRejectionListener(new InvitationRejectionListener() {
public void invitationDeclined(String invitee, String reason) {
// Do whatever you need here...
System.out.println("Initee "+invitee+" reason"+reason);
}
});
} catch (XMPPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void setConnection(XMPPConnection connection) {
this.connection = connection;
if (connection != null) {
// Add a packet listener to get messages sent to us
PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
connection.addPacketListener(new PacketListener() {
public void processPacket(Packet packet) {
Message message = (Message) packet;
if (message.getBody() != null) {
String fromName = StringUtils.parseBareAddress(message
.getFrom());
Log.i("XMPPClient", "Got text [" + message.getBody()
+ "] from [" + fromName + "]");
messages.add(fromName + ":");
messages.add(message.getBody());
// Add the incoming message to the list view
mHandler.post(new Runnable() {
public void run() {
setListAdapter();
checkInvitation();
}
});
}
}
}, filter);
mHandler.post(new Runnable() {
public void run() {
checkInvitation();
}
});
}
}
The 404 error indicates that:
404 error can occur if the room does not exist or is locked
So, ensure that your room is not locked or existed! The code below is how I join the room when there's an in-comming invitation:
private void setChatRoomInvitationListener() {
MultiUserChat.addInvitationListener(mXmppConnection,
new InvitationListener() {
#Override
public void invitationReceived(Connection connection,
String room, String inviter, String reason,
String unKnown, Message message) {
//MultiUserChat.decline(mXmppConnection, room, inviter,
// "Don't bother me right now");
// MultiUserChat.decline(mXmppConnection, room, inviter,
// "Don't bother me right now");
try {
muc.join("test-nick-name");
Log.e("abc","join room successfully");
muc.sendMessage("I joined this room!! Bravo!!");
} catch (XMPPException e) {
e.printStackTrace();
Log.e("abc","join room failed!");
}
}
});
}
Hope this helps your error!
Edit:this is how I config the room:
/*
* Create room
*/
muc.create(roomName);
// muc.sendConfigurationForm(new Form(Form.TYPE_SUBMIT));
Form form = muc.getConfigurationForm();
Form submitForm = form.createAnswerForm();
for (Iterator fields = form.getFields(); fields.hasNext();) {
FormField field = (FormField) fields.next();
if (!FormField.TYPE_HIDDEN.equals(field.getType())
&& field.getVariable() != null) {
show("field: " + field.getVariable());
// Sets the default value as the answer
submitForm.setDefaultAnswer(field.getVariable());
}
}
List<String> owners = new ArrayList<String>();
owners.add(DataConfig.USERNAME + "#" + DataConfig.SERVICE);
submitForm.setAnswer("muc#roomconfig_roomowners", owners);
submitForm.setAnswer("muc#roomconfig_roomname", roomName);
submitForm.setAnswer("muc#roomconfig_persistentroom", true);
muc.sendConfigurationForm(submitForm);
// submitForm.
show("created room!");
muc.addMessageListener(new PacketListener() {
#Override
public void processPacket(Packet packet) {
show(packet.toXML());
Message mess = (Message) packet;
showMessageToUI(mess.getFrom() + ": " + mess.getBody());
}
});
With this cofiguration, I can join a room easily without password.
You may use the code snippet to join the chat:
public void joinMultiUserChatRoom(String userName, String roomName) {
// Get the MultiUserChatManager
MultiUserChatManager manager = MultiUserChatManager.getInstanceFor(connection);
// Create a MultiUserChat using an XMPPConnection for a room
MultiUserChat multiUserChat = manager.getMultiUserChat(roomName + "#conference.localhost");
DiscussionHistory history = new DiscussionHistory();
history.setMaxStanzas(-1);
try {
multiUserChat.join(userName, "", history, connection.getPacketReplyTimeout());
} catch (Exception e) {
e.printStackTrace();
}
}
Invite a friend:
/**
* Invites another user to this room.
*
* #param userAddress the address of the user to invite to the room.(one
* may also invite users not on their contact list).
* #param reason a reason, subject, or welcome message that would tell
* the the user why they are being invited.
*/
public void invite(String userAddress, String reason)
{
multiUserChat.invite(userAddress, reason);
}

modifying a map while iterating over its entrySet

In the java docs of the map interface's entrySet() method I found this statement and I really do no understand it.
The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress, the results of the iteration are undefined
what is meant by undefined here?
For more clarification, this is my situation.
I have a web application based on spring & hibernate.
Our team implemented custom caching class called CachedIntegrationClients.
We are using RabbitMQ as a messaging server.
instead of getting our clients each time we want to send a message to the server, we cache the clients using the previous caching class.
The problem is that the messages are sent to the messaging server twice.
Viewing the logs, we found that the method that get the cached clients return the client twice, although this (theoretically) impossible as we store the clients in a map, and the map does not allow duplicate keys.
After some smoke viewing of the code I found that the method that iterates over the cached clients gets a set of the clients from the cached clients map.
So I suspected that while iterating over this set, another request is made by another client and this client may be uncached, so it modifies the map.
Any way this is the CachedIntegrationClients class
public class CachedIntegrationClientServiceImpl {
private IntegrationDao integrationDao;
private IntegrationService integrationService;
Map<String, IntegrationClient> cachedIntegrationClients = null;
#Override
public void setBaseDAO(BaseDao baseDao) {
super.setBaseDAO(integrationDao);
}
#Override
public void refreshCache() {
cachedIntegrationClients = null;
}
synchronized private void putOneIntegrationClientOnCache(IntegrationClient integrationClient){
fillCachedIntegrationClients(); // only fill cache if it is null , it will never refill cache
if (! cachedIntegrationClients.containsValue(integrationClient)) {
cachedIntegrationClients.put(integrationClient.getClientSlug(),integrationClient);
}
}
/**
* only fill cache if it is null , it will never refill cache
*/
private void fillCachedIntegrationClients() {
if (cachedIntegrationClients != null) {
return ;
}
log.debug("filling cache of cachedClients");
cachedIntegrationClients = new HashMap<String, IntegrationClient>(); // initialize cache Map
List<IntegrationClient> allCachedIntegrationClients= integrationDao.getAllIntegrationClients();
if (allCachedIntegrationClients != null) {
for (IntegrationClient integrationClient : allCachedIntegrationClients) {
integrationService
.injectCssFileForIntegrationClient(integrationClient);
fetchClientServiceRelations(integrationClient
.getIntegrationClientServiceList());
}
for (IntegrationClient integrationClient : allCachedIntegrationClients) {
putOneIntegrationClientOnCache(integrationClient);
}
}
}
/**
* fetch all client service
* #param integrationClientServiceList
*/
private void fetchClientServiceRelations(
List<IntegrationClientService> integrationClientServiceList) {
for (IntegrationClientService integrationClientService : integrationClientServiceList) {
fetchClientServiceRelations(integrationClientService);
}
}
private void fetchClientServiceRelations(IntegrationClientService clientService) {
for (Exchange exchange : clientService.getExchangeList()) {
exchange.getId();
}
for (Company company : clientService.getCompanyList()) {
company.getId();
}
}
/**
* Get a client given its slug.
*
* If the client was not found, an exception will be thrown.
*
* #throws ClientNotFoundIntegrationException
* #return IntegrationClient
*/
#Override
public IntegrationClient getIntegrationClient(String clientSlug) throws ClientNotFoundIntegrationException {
if (cachedIntegrationClients == null) {
fillCachedIntegrationClients();
}
if (!cachedIntegrationClients.containsKey(clientSlug)) {
IntegrationClient integrationClient = integrationDao.getIntegrationClient(clientSlug);
if (integrationClient != null) {
this.fetchClientServiceRelations(integrationClient.getIntegrationClientServiceList());
integrationService.injectCssFileForIntegrationClient(integrationClient);
cachedIntegrationClients.put(clientSlug, integrationClient);
}
}
IntegrationClient client = cachedIntegrationClients.get(clientSlug);
if (client == null) {
throw ClientNotFoundIntegrationException.forClientSlug(clientSlug);
}
return client;
}
public void setIntegrationDao(IntegrationDao integrationDao) {
this.integrationDao = integrationDao;
}
public IntegrationDao getIntegrationDao() {
return integrationDao;
}
public Map<String, IntegrationClient> getCachedIntegrationClients() {
if (cachedIntegrationClients == null) {
fillCachedIntegrationClients();
}
return cachedIntegrationClients;
}
public IntegrationService getIntegrationService() {
return integrationService;
}
public void setIntegrationService(IntegrationService integrationService) {
this.integrationService = integrationService;
}
}
and here is the method that iterates over the set
public List<IntegrationClientService> getIntegrationClientServicesForService(IntegrationServiceModel service) {
List<IntegrationClientService> integrationClientServices = new ArrayList<IntegrationClientService>();
for (Entry<String, IntegrationClient> entry : cachedIntegrationClientService.getCachedIntegrationClients().entrySet()) {
IntegrationClientService integrationClientService = getIntegrationClientService(entry.getValue(), service);
if (integrationClientService != null) {
integrationClientServices.add(integrationClientService);
}
}
return integrationClientServices;
}
Also here is the method that calls the previous one
List<IntegrationClientService> clients = integrationService.getIntegrationClientServicesForService(service);
System.out.println(clients.size());
if (clients.size() > 0) {
log.info("Inbound service message [" + messageType.getKey() + "] to be sent to " + clients.size()
+ " registered clients: [" + StringUtils.arrayToDelimitedString(clients.toArray(), ", ") + "]");
for (IntegrationClientService integrationClientService : clients) {
Message<T> message = integrationMessageBuilder.build(messageType, payload, integrationClientService);
try {
channel.send(message);
} catch (RuntimeException e) {
messagingIntegrationService.handleException(e, messageType, integrationClientService, payload);
}
}
} else {
log.info("Inbound service message [" + messageType.getKey() + "] but no registered clients, not taking any further action.");
}
and here is the logs that appears on the server
BaseIntegrationGateway.createAndSendToSubscribers(65) | Inbound service message [news.create] to be sent to 3 registered clients: [Id=126, Service=IntegrationService.MESSAGE_NEWS, Client=MDC, Id=125, Service=IntegrationService.MESSAGE_NEWS, Client=CNBC, Id=125, Service=IntegrationService.MESSAGE_NEWS, Client=CNBC]
Undefined means there is no requirement for any specific behavior. The implementation is free to start WWIII, re-hang all your toilet rolls by the overhand method, sully your grandmother, etc.
The only permitted modification with a specified behaviour is via the iterator.
Have you looked at java.concurrent.ConcurrentHashMap?
EDIT: I looked over your code again this stikes me as odd:
In fillCachedIntegrationClients() you have the following loop:
for (IntegrationClient integrationClient : allCachedIntegrationClients) {
putOneIntegrationClientOnCache(integrationClient);
}
But the putOneIntegrationClientOnCache method itself directly calls fillCachedIntegrationClients();
synchronized private void putOneIntegrationClientOnCache(IntegrationClient integrationClient){
fillCachedIntegrationClients(); // only fill cache if it is null , it will never refill cache
...
}
Something there must go wrong. You are calling fillCachedIntegrationClients() twice. Actually if I am not mistaken this should actually be a never-ending loop since one method calls the other and vice versa. The != null condition is never met during the initialization. Ofcourse you are modifying and iterating in a undefined way so maybe that saves you from an infinite loop.

Categories