From f9ac08032c4e73f79c53dbaf7f205c1287a8fe32 Mon Sep 17 00:00:00 2001 From: Simon Pamies Date: Thu, 20 Jun 2013 15:04:01 +0200 Subject: [PATCH] a) Bulk of changes related to UI - making the replication tab a better world :-) b) Added unique identifier for each replica. This now allows to have multiple replicas per physical host. It also make deregistration deterministic. --- .../gwt/ui/adminconsole/ReplicationPanel.java | 110 +++++++++++++----- .../sailing/gwt/ui/client/SailingService.java | 2 + .../gwt/ui/client/SailingServiceAsync.java | 2 + .../sailing/gwt/ui/client/StringMessages.java | 1 + .../gwt/ui/client/StringMessages.properties | 3 +- .../ui/client/StringMessages_de.properties | 3 +- .../gwt/ui/server/SailingServiceImpl.java | 14 ++- .../sap/sailing/gwt/ui/shared/ReplicaDTO.java | 7 +- .../gwt/ui/shared/ReplicationStateDTO.java | 8 +- .../test/AbstractServerReplicationTest.java | 3 +- ...nstancesManagerLoggingPerformanceTest.java | 3 +- .../ReplicationMasterDescriptor.java | 5 +- .../replication/ReplicationService.java | 13 +++ .../replication/impl/ReplicaDescriptor.java | 12 +- .../impl/ReplicationInstancesManager.java | 5 + .../impl/ReplicationMasterDescriptorImpl.java | 15 ++- .../impl/ReplicationServiceImpl.java | 33 +++++- .../replication/impl/ReplicationServlet.java | 9 +- .../server/impl/RacingEventServiceImpl.java | 9 +- 19 files changed, 203 insertions(+), 54 deletions(-) diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ReplicationPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ReplicationPanel.java index f6984db16e9..9d871f66d6c 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ReplicationPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ReplicationPanel.java @@ -6,10 +6,13 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.CaptionPanel; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Grid; +import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.domain.common.impl.Util.Pair; import com.sap.sailing.domain.common.impl.Util.Triple; @@ -40,21 +43,40 @@ public class ReplicationPanel extends FlowPanel { private final Button addButton; private final Button stopReplicationButton; + private final Button removeAllReplicas; public ReplicationPanel(SailingServiceAsync sailingService, ErrorReporter errorReporter, StringMessages stringMessages) { this.sailingService = sailingService; this.stringMessages = stringMessages; this.errorReporter = errorReporter; - add(new Label(stringMessages.explainReplicasRegistered())); + final CaptionPanel mastergroup = new CaptionPanel(stringMessages.explainReplicasRegistered()); + final VerticalPanel masterpanel = new VerticalPanel(); + registeredReplicas = new Grid(); registeredReplicas.resizeColumns(3); - add(registeredReplicas); + masterpanel.add(registeredReplicas); + + removeAllReplicas = new Button(stringMessages.stopAllReplicas()); + removeAllReplicas.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + stopAllReplicas(); + }; + }); + removeAllReplicas.setEnabled(false); + masterpanel.add(removeAllReplicas); + + mastergroup.add(masterpanel); + add(mastergroup); + + final CaptionPanel replicagroup = new CaptionPanel(stringMessages.explainConnectionsToMaster()); + final VerticalPanel replicapanel = new VerticalPanel(); + final HorizontalPanel replicapanelbuttons = new HorizontalPanel(); - add(new Label(stringMessages.explainConnectionsToMaster())); registeredMasters = new Grid(); registeredMasters.resizeColumns(3); - add(registeredMasters); + replicapanel.add(registeredMasters); Button refreshButton = new Button(stringMessages.refresh()); refreshButton.addClickHandler(new ClickHandler() { @@ -63,7 +85,7 @@ public class ReplicationPanel extends FlowPanel { updateReplicaList(); } }); - add(refreshButton); + replicapanelbuttons.add(refreshButton); addButton = new Button(stringMessages.connectToMaster()); addButton.addClickHandler(new ClickHandler() { @Override @@ -71,7 +93,7 @@ public class ReplicationPanel extends FlowPanel { addReplication(); } }); - add(addButton); + replicapanelbuttons.add(addButton); stopReplicationButton = new Button(stringMessages.stopConnectionToMaster()); stopReplicationButton.addClickHandler(new ClickHandler() { @Override @@ -80,10 +102,29 @@ public class ReplicationPanel extends FlowPanel { }; }); stopReplicationButton.setEnabled(false); - add(stopReplicationButton); + replicapanelbuttons.add(stopReplicationButton); + + replicapanel.add(replicapanelbuttons); + replicagroup.add(replicapanel); + add(replicagroup); updateReplicaList(); } + protected void stopAllReplicas() { + sailingService.stopAllReplicas(new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + errorReporter.reportError(caught.getMessage()); + updateReplicaList(); + } + @Override + public void onSuccess(Void result) { + removeAllReplicas.setEnabled(false); + updateReplicaList(); + } + }); + } + private void stopReplication() { stopReplicationButton.setEnabled(false); sailingService.stopReplicatingFromMaster(new AsyncCallback() { @@ -144,10 +185,41 @@ public class ReplicationPanel extends FlowPanel { sailingService.getReplicaInfo(new AsyncCallback() { @Override public void onSuccess(ReplicationStateDTO replicas) { + int i=0; + while (registeredReplicas.getRowCount() > 0) { + registeredReplicas.removeRow(0); + } + boolean replicaRegistered = false; + for (ReplicaDTO replica : replicas.getReplicas()) { + registeredReplicas.insertRow(i); + registeredReplicas.setWidget(i, 0, new Label((i+1) + ". " + replica.getHostname() + " (" + replica.getIdentifier() + ")")); + registeredReplicas.setWidget(i, 1, new Label(stringMessages.registeredAt(replica.getRegistrationTime().toString()))); + i++; + for (Map.Entry e : replica.getOperationCountByOperationClassName().entrySet()) { + registeredReplicas.insertRow(i); + registeredReplicas.setWidget(i, 1, new Label(e.getKey())); + registeredReplicas.setWidget(i, 2, new Label(e.getValue().toString())); + i++; + } + replicaRegistered = true; + } + + if (!replicaRegistered) { + registeredReplicas.insertRow(i); + registeredReplicas.setWidget(i, 0, new Label(stringMessages.explainNoConnectionsFromReplicas())); + } else { + removeAllReplicas.setEnabled(true); + } + while (registeredMasters.getRowCount() > 0) { registeredMasters.removeRow(0); } - int i=0; + i = 0; + + registeredMasters.insertRow(i); + registeredMasters.setWidget(i, 0, new Label("Client UUID: " + replicas.getServerIdentifier())); + i++; + final ReplicationMasterDTO replicatingFromMaster = replicas.getReplicatingFromMaster(); if (replicatingFromMaster != null) { registeredMasters.insertRow(i); @@ -163,28 +235,6 @@ public class ReplicationPanel extends FlowPanel { stopReplicationButton.setEnabled(false); } - while (registeredReplicas.getRowCount() > 0) { - registeredReplicas.removeRow(0); - } - i = 0; boolean replicaRegistered = false; - for (ReplicaDTO replica : replicas.getReplicas()) { - registeredReplicas.insertRow(i); - registeredReplicas.setWidget(i, 0, new Label(replica.getHostname())); - registeredReplicas.setWidget(i, 1, new Label(stringMessages.registeredAt(replica.getRegistrationTime().toString()))); - i++; - for (Map.Entry e : replica.getOperationCountByOperationClassName().entrySet()) { - registeredReplicas.insertRow(i); - registeredReplicas.setWidget(i, 1, new Label(e.getKey())); - registeredReplicas.setWidget(i, 2, new Label(e.getValue().toString())); - i++; - } - replicaRegistered = true; - } - - if (!replicaRegistered) { - registeredReplicas.insertRow(i); - registeredReplicas.setWidget(i, 0, new Label(stringMessages.explainNoConnectionsFromReplicas())); - } } @Override diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index ff7a8e06f68..edef7138916 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -311,4 +311,6 @@ public interface SailingService extends RemoteService { String getBuildVersion(); void stopReplicatingFromMaster(); + + void stopAllReplicas(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index 59fd4bd557b..ab258cb7042 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -431,6 +431,8 @@ public interface SailingServiceAsync { void getRaceStateEntriesForRaceGroup(String eventIdAsString, List visibleCourseAreas, List visibleRegattas, boolean showOnlyCurrentlyRunningRaces, boolean showOnlyRacesOfSameDay, AsyncCallback> markedAsyncCallback); + + void stopAllReplicas(AsyncCallback asyncCallback); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java index 6d5b33ab6ca..52c522f0038 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java @@ -682,4 +682,5 @@ public interface StringMessages extends Messages { String raceAbandoned(); String raceAbandonedNoMoreRacingToday(); String raceAbandonedFurtherSignalsAshore(); + String stopAllReplicas(); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties index 64a9e126260..2d156508043 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties @@ -674,4 +674,5 @@ startPostponedNoMoreRacingToday=Start postponed - No more racing today startPostponedFurtherSignalsAshore=Start postponed - Further signals ashore raceAbandoned=Race abandoned raceAbandonedNoMoreRacingToday=Race abandoned - No more racing today -raceAbandonedFurtherSignalsAshore=Race abandoned - Further signals ashore \ No newline at end of file +raceAbandonedFurtherSignalsAshore=Race abandoned - Further signals ashore +stopAllReplicas=Drop connection to all replicas (Dangerous!) \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties index 8f6ca50302a..12c1f3aade4 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties @@ -660,4 +660,5 @@ explainNoConnectionsToMaster=Es sind keine Verbindungen zu einem Master Server k explainNoConnectionsFromReplicas=Es sind keine Verbindugen von Replicas registriert. stopConnectionToMaster=Replikation anhalten raceAbandonedNoMoreRacingToday=Rennabbruch - heute keine Rennen mehr -raceAbandonedFurtherSignalsAshore=Rennabbruch - weitere Signale an Land \ No newline at end of file +raceAbandonedFurtherSignalsAshore=Rennabbruch - weitere Signale an Land +stoppAllReplicas=Verbindung zu allen Replicas abbrechen \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index f50043c6830..20728bb53be 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -2429,7 +2429,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S for (Map.Entry>, Integer> e : statistics.entrySet()) { replicationCountByOperationClassName.put(e.getKey().getName(), e.getValue()); } - replicaDTOs.add(new ReplicaDTO(replicaDescriptor.getIpAddress().getHostName(), replicaDescriptor.getRegistrationTime().asDate(), + replicaDTOs.add(new ReplicaDTO(replicaDescriptor.getIpAddress().getHostName(), replicaDescriptor.getRegistrationTime().asDate(), replicaDescriptor.getUuid().toString(), replicationCountByOperationClassName)); } ReplicationMasterDTO master; @@ -2440,7 +2440,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S master = new ReplicationMasterDTO(replicatingFromMaster.getHostname(), replicatingFromMaster.getMessagingPort(), replicatingFromMaster.getServletPort()); } - return new ReplicationStateDTO(master, replicaDTOs); + return new ReplicationStateDTO(master, replicaDTOs, service.getServerIdentifier().toString()); } @Override @@ -3087,4 +3087,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S throw new RuntimeException(e); } } + + @Override + public void stopAllReplicas() { + try { + getReplicationService().stopAllReplica(); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/ReplicaDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/ReplicaDTO.java index d82daf737f3..3528961b5df 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/ReplicaDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/ReplicaDTO.java @@ -7,12 +7,14 @@ import com.google.gwt.user.client.rpc.IsSerializable; public class ReplicaDTO implements IsSerializable { private String hostname; + private String identifier; private Date registrationTime; private Map operationCountByOperationClassName; ReplicaDTO() {} public ReplicaDTO(String hostname, Date registrationTime, - Map operationCountByOperationClassName) { + String identifier, Map operationCountByOperationClassName) { this.hostname = hostname; + this.identifier = identifier; this.registrationTime = registrationTime; this.operationCountByOperationClassName = operationCountByOperationClassName; } @@ -25,4 +27,7 @@ public class ReplicaDTO implements IsSerializable { public Map getOperationCountByOperationClassName() { return operationCountByOperationClassName; } + public String getIdentifier() { + return identifier; + } } \ No newline at end of file diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/ReplicationStateDTO.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/ReplicationStateDTO.java index d4c53de2800..dfd65272a7e 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/ReplicationStateDTO.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/shared/ReplicationStateDTO.java @@ -14,11 +14,13 @@ import com.google.gwt.user.client.rpc.IsSerializable; public class ReplicationStateDTO implements IsSerializable { private Map replicaInfoByHostname; private ReplicationMasterDTO replicatingFromMaster; + private String serverIdentifier; ReplicationStateDTO() { } // for de-serialization - public ReplicationStateDTO(ReplicationMasterDTO replicatingFromMaster, Iterable replicas) { + public ReplicationStateDTO(ReplicationMasterDTO replicatingFromMaster, Iterable replicas, String serverIdentifier) { this.replicatingFromMaster = replicatingFromMaster; + this.serverIdentifier = serverIdentifier; this.replicaInfoByHostname = new HashMap(); for (ReplicaDTO replica : replicas) { replicaInfoByHostname.put(replica.getHostname(), replica); @@ -36,4 +38,8 @@ public class ReplicationStateDTO implements IsSerializable { public ReplicaDTO getReplicaByHostname(String hostname) { return replicaInfoByHostname.get(hostname); } + + public String getServerIdentifier() { + return serverIdentifier; + } } \ No newline at end of file diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractServerReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractServerReplicationTest.java index 95b42443bd2..f920c0ec696 100755 --- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractServerReplicationTest.java +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractServerReplicationTest.java @@ -71,6 +71,7 @@ public abstract class AbstractServerReplicationTest { protected Pair basicSetUp( boolean dropDB, RacingEventServiceImpl master, RacingEventServiceImpl replica) throws IOException, InterruptedException { final String exchangeName = "test-sapsailinganalytics-exchange"; + final UUID serverUuid = UUID.randomUUID(); final MongoDBService mongoDBService = MongoDBService.INSTANCE; if (dropDB) { mongoDBService.getDB().dropDatabase(); @@ -88,7 +89,7 @@ public abstract class AbstractServerReplicationTest { } ReplicationInstancesManager rim = new ReplicationInstancesManager(); masterReplicator = new ReplicationServiceImpl(exchangeName, rim, this.master); - replicaDescriptor = new ReplicaDescriptor(InetAddress.getLocalHost()); + replicaDescriptor = new ReplicaDescriptor(InetAddress.getLocalHost(), serverUuid, ""); masterReplicator.registerReplica(replicaDescriptor); ReplicationMasterDescriptor masterDescriptor = new ReplicationMasterDescriptorImpl("localhost", exchangeName, SERVLET_PORT, 0); ReplicationServiceTestImpl replicaReplicator = new ReplicationServiceTestImpl(exchangeName, resolveAgainst, rim, diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/ReplicationInstancesManagerLoggingPerformanceTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/ReplicationInstancesManagerLoggingPerformanceTest.java index 9f6ca93ad66..dabf92a4cd7 100755 --- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/ReplicationInstancesManagerLoggingPerformanceTest.java +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/ReplicationInstancesManagerLoggingPerformanceTest.java @@ -5,6 +5,7 @@ import static org.junit.Assert.assertEquals; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; +import java.util.UUID; import org.junit.Before; import org.junit.Test; @@ -21,7 +22,7 @@ public class ReplicationInstancesManagerLoggingPerformanceTest { @Before public void setUp() throws UnknownHostException { replicationInstanceManager = new ReplicationInstancesManager(); - replica = new ReplicaDescriptor(InetAddress.getLocalHost()); + replica = new ReplicaDescriptor(InetAddress.getLocalHost(), UUID.randomUUID(), ""); replicationInstanceManager.registerReplica(replica); operation = new CreateLeaderboardGroup("Test Leaderboard Group", "Description of Test Leaderboard Group", /* displayGroupsInReverseOrder */ false, Arrays.asList(new String[] { "Default Leaderboard" }), /* overallLeaderboardDiscardThresholds */ null, /* overallLeaderboardScoringSchemeType */ null); diff --git a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/ReplicationMasterDescriptor.java b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/ReplicationMasterDescriptor.java index 46c46dbc994..85a4814f420 100644 --- a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/ReplicationMasterDescriptor.java +++ b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/ReplicationMasterDescriptor.java @@ -3,6 +3,7 @@ package com.sap.sailing.server.replication; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.UUID; import com.rabbitmq.client.QueueingConsumer; @@ -14,9 +15,9 @@ import com.rabbitmq.client.QueueingConsumer; */ public interface ReplicationMasterDescriptor { - URL getReplicationRegistrationRequestURL() throws MalformedURLException; + URL getReplicationRegistrationRequestURL(UUID uuid, String additionalInformation) throws MalformedURLException; - URL getReplicationDeRegistrationRequestURL() throws MalformedURLException; + URL getReplicationDeRegistrationRequestURL(UUID uuid) throws MalformedURLException; URL getInitialLoadURL() throws MalformedURLException; diff --git a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/ReplicationService.java b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/ReplicationService.java index 0f1c1678b52..35230083a75 100644 --- a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/ReplicationService.java +++ b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/ReplicationService.java @@ -2,6 +2,7 @@ package com.sap.sailing.server.replication; import java.io.IOException; import java.util.Map; +import java.util.UUID; import com.sap.sailing.server.RacingEventServiceOperation; import com.sap.sailing.server.replication.impl.ReplicaDescriptor; @@ -49,4 +50,16 @@ public interface ReplicationService { * @throws IOException */ void stopToReplicateFromMaster() throws IOException; + + /** + * Stops all replica currently registered with this server. + * @throws IOException + */ + void stopAllReplica() throws IOException; + + /** + * Returns an unique server identifier + * @return + */ + UUID getServerIdentifier(); } diff --git a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicaDescriptor.java b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicaDescriptor.java index 34c8923673c..e7cdee07842 100644 --- a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicaDescriptor.java +++ b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicaDescriptor.java @@ -18,18 +18,18 @@ public class ReplicaDescriptor implements Serializable { private static final long serialVersionUID = -5451556877949921454L; private final UUID uuid; - private final InetAddress ipAddress; - private final TimePoint registrationTime; + private final String additionalInformation; /** * Sets the registration time to now. */ - public ReplicaDescriptor(InetAddress ipAddress) { - this.uuid = UUID.randomUUID(); + public ReplicaDescriptor(InetAddress ipAddress, UUID serverUuid, String additionalInformation) { + this.uuid = serverUuid; this.registrationTime = MillisecondsTimePoint.now(); this.ipAddress = ipAddress; + this.additionalInformation = additionalInformation; } public UUID getUuid() { @@ -43,6 +43,10 @@ public class ReplicaDescriptor implements Serializable { public TimePoint getRegistrationTime() { return registrationTime; } + + public String getAdditionalInformation() { + return additionalInformation; + } @Override public int hashCode() { diff --git a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationInstancesManager.java b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationInstancesManager.java index 3d8bcd57248..7ce3e343df6 100644 --- a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationInstancesManager.java +++ b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationInstancesManager.java @@ -85,4 +85,9 @@ public class ReplicationInstancesManager { public Map>, Integer> getStatistics(ReplicaDescriptor replica) { return replicationCounts.get(replica); } + + public void removeAll() { + replicationCounts.clear(); + replicaDescriptors.clear(); + } } diff --git a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationMasterDescriptorImpl.java b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationMasterDescriptorImpl.java index e40d9eeba99..788d72f15a7 100755 --- a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationMasterDescriptorImpl.java +++ b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationMasterDescriptorImpl.java @@ -3,12 +3,14 @@ package com.sap.sailing.server.replication.impl; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.UUID; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.QueueingConsumer; import com.sap.sailing.server.replication.ReplicationMasterDescriptor; +import com.sap.sailing.util.BuildVersion; public class ReplicationMasterDescriptorImpl implements ReplicationMasterDescriptor { private static final String REPLICATION_SERVLET = "/replication/replication"; @@ -28,15 +30,18 @@ public class ReplicationMasterDescriptorImpl implements ReplicationMasterDescrip } @Override - public URL getReplicationRegistrationRequestURL() throws MalformedURLException { + public URL getReplicationRegistrationRequestURL(UUID uuid, String additional) throws MalformedURLException { return new URL("http", hostname, servletPort, REPLICATION_SERVLET + "?" + ReplicationServlet.ACTION + "=" - + ReplicationServlet.Action.REGISTER.name()); + + ReplicationServlet.Action.REGISTER.name() + + "&" + ReplicationServlet.SERVER_UUID + "=" + uuid.toString() + + "&" + ReplicationServlet.ADDITIONAL_INFORMATION + "=" + BuildVersion.getBuildVersion()); } @Override - public URL getReplicationDeRegistrationRequestURL() throws MalformedURLException { + public URL getReplicationDeRegistrationRequestURL(UUID uuid) throws MalformedURLException { return new URL("http", hostname, servletPort, REPLICATION_SERVLET + "?" + ReplicationServlet.ACTION + "=" - + ReplicationServlet.Action.DEREGISTER.name()); + + ReplicationServlet.Action.DEREGISTER.name() + + "&" + ReplicationServlet.SERVER_UUID + "=" + uuid.toString()); } @Override @@ -85,5 +90,5 @@ public class ReplicationMasterDescriptorImpl implements ReplicationMasterDescrip public String getExchangeName() { return exchangeName; } - + } diff --git a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationServiceImpl.java b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationServiceImpl.java index 1af7a1f486c..ada7938d8db 100644 --- a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationServiceImpl.java +++ b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationServiceImpl.java @@ -10,6 +10,7 @@ import java.net.URL; import java.net.URLConnection; import java.util.HashMap; import java.util.Map; +import java.util.UUID; import java.util.logging.Logger; import org.osgi.util.tracker.ServiceTracker; @@ -23,6 +24,7 @@ import com.sap.sailing.server.RacingEventService; import com.sap.sailing.server.RacingEventServiceOperation; import com.sap.sailing.server.replication.ReplicationMasterDescriptor; import com.sap.sailing.server.replication.ReplicationService; +import com.sap.sailing.util.BuildVersion; /** * Can observe a {@link RacingEventService} for the operations it performs that require replication. Only observes as @@ -69,6 +71,11 @@ public class ReplicationServiceImpl implements ReplicationService, OperationExec */ private final String exchangeName; + /** + * UUID that identifies this server + */ + private final UUID serverUUID; + private Replicator replicator; private Thread replicatorThread; @@ -81,6 +88,7 @@ public class ReplicationServiceImpl implements ReplicationService, OperationExec localService = null; this.exchangeName = exchangeName; replicator = null; + serverUUID = UUID.randomUUID(); } /** @@ -95,6 +103,7 @@ public class ReplicationServiceImpl implements ReplicationService, OperationExec this.localService = localService; this.exchangeName = exchangeName; replicator = null; + serverUUID = UUID.randomUUID(); } private Channel createMasterChannel(String exchangeName) throws IOException { @@ -220,7 +229,7 @@ public class ReplicationServiceImpl implements ReplicationService, OperationExec * @return the UUID that the master generated for this client which is also entered into {@link #replicaUUIDs} */ private String registerReplicaWithMaster(ReplicationMasterDescriptor master) throws IOException, ClassNotFoundException { - URL replicationRegistrationRequestURL = master.getReplicationRegistrationRequestURL(); + URL replicationRegistrationRequestURL = master.getReplicationRegistrationRequestURL(getServerIdentifier(), BuildVersion.getBuildVersion()); final URLConnection registrationRequestConnection = replicationRegistrationRequestURL.openConnection(); registrationRequestConnection.connect(); InputStream content = (InputStream) registrationRequestConnection.getContent(); @@ -238,7 +247,7 @@ public class ReplicationServiceImpl implements ReplicationService, OperationExec protected void deregisterReplicaWithMaster(ReplicationMasterDescriptor master) { try { - URL replicationDeRegistrationRequestURL = master.getReplicationDeRegistrationRequestURL(); + URL replicationDeRegistrationRequestURL = master.getReplicationDeRegistrationRequestURL(getServerIdentifier()); final URLConnection deregistrationRequestConnection = replicationDeRegistrationRequestURL.openConnection(); deregistrationRequestConnection.connect(); StringBuilder uuid = new StringBuilder(); @@ -293,4 +302,24 @@ public class ReplicationServiceImpl implements ReplicationService, OperationExec } } + @Override + public void stopAllReplica() throws IOException { + if (replicationInstancesManager.hasReplicas()) { + replicationInstancesManager.removeAll(); + removeAsListenerFromRacingEventService(); + synchronized (this) { + if (masterChannel != null) { + masterChannel.close(); + masterChannel = null; + } + } + logger.info("Unregistered all replicas from this server!"); + } + } + + @Override + public UUID getServerIdentifier() { + return serverUUID; + } + } diff --git a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationServlet.java b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationServlet.java index 1bc9bce67df..b1693988d26 100755 --- a/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationServlet.java +++ b/java/com.sap.sailing.server.replication/src/com/sap/sailing/server/replication/impl/ReplicationServlet.java @@ -5,6 +5,7 @@ import java.io.ObjectOutputStream; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; +import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -34,6 +35,8 @@ public class ReplicationServlet extends SailingServerHttpServlet { public enum Action { REGISTER, INITIAL_LOAD, DEREGISTER } public static final String ACTION = "action"; + public static final String SERVER_UUID = "uuid"; + public static final String ADDITIONAL_INFORMATION = "additional"; private ServiceTracker replicationServiceTracker; @@ -98,8 +101,10 @@ public class ReplicationServlet extends SailingServerHttpServlet { } private ReplicaDescriptor getReplicaDescriptor(HttpServletRequest req) throws UnknownHostException { - // XXX: this can lead to problems if there are multiple replicas on one server InetAddress ipAddress = InetAddress.getByName(req.getRemoteAddr()); - return new ReplicaDescriptor(ipAddress); + UUID uuid = UUID.fromString(req.getParameter(SERVER_UUID)); + String additional = req.getParameter(ADDITIONAL_INFORMATION); + logger.info("Registered new replica " + ipAddress + " " + uuid.toString() + " " + additional); + return new ReplicaDescriptor(ipAddress, uuid, additional); } } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java index 0fa3f8d5e8d..13c4ad81cd9 100755 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/RacingEventServiceImpl.java @@ -1648,32 +1648,39 @@ public class RacingEventServiceImpl implements RacingEventService, RegattaListen public void serializeForInitialReplication(ObjectOutputStream oos) throws IOException { StringBuffer logoutput = new StringBuffer(); + logger.info("Serializing events..."); oos.writeObject(eventsById); logoutput.append("\nSerialized " + eventsById.size() + " events\n"); for (Event event : eventsById.values()) { logoutput.append(String.format("%3s\n", event.toString())); } + logger.info("Serializing regattas..."); oos.writeObject(regattasByName); logoutput.append("Serialized " + regattasByName.size() + " regattas\n"); for (Regatta regatta : regattasByName.values()) { logoutput.append(String.format("%3s\n", regatta.toString())); } - + + logger.info("Serializing regattas observed..."); oos.writeObject(regattasObservedForDefaultLeaderboard); + logger.info("Serializing regatta tracking cache..."); oos.writeObject(regattaTrackingCache); + logger.info("Serializing leaderboard groups..."); oos.writeObject(leaderboardGroupsByName); logoutput.append("Serialized " + leaderboardGroupsByName.size() + " leaderboard groups\n"); for (LeaderboardGroup lg : leaderboardGroupsByName.values()) { logoutput.append(String.format("%3s\n", lg.toString())); } + logger.info("Serializing leaderboards..."); oos.writeObject(leaderboardsByName); logoutput.append("Serialized " + leaderboardsByName.size() + " leaderboards\n"); for (Leaderboard lg : leaderboardsByName.values()) { logoutput.append(String.format("%3s\n", lg.toString())); } + logger.info("Serializing media library..."); mediaLibrary.serialize(oos); logoutput.append("Serialized " + mediaLibrary.allTracks().size() + " media tracks\n"); for (MediaTrack lg : mediaLibrary.allTracks()) {