public void onServerJoin(ServerJoinEvent e){
		handleMessage("DistributedHashTable - onServerJoin: server " +  e.getServerId() + " joind");
		joinServerId = e.getServerId();
		// skip if back up successor comes back online
		if(joinServerId == this.backupSuccessor.getKey())
			return;
		
		// run the update on a worker thread
		try {
			SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
				@Override
				protected Void doInBackground() throws Exception {
					String onlineServerAddress =  successorTable.get(joinServerId);
					ReplicationStorage repServer = getReplicationStorage(joinServerId);				
									
					// make sure the other replication machine is online, if it is off online, 
					// make the update dirty to be synced later with other replication in case master failed.
		        	Map.Entry<Integer, String> nextLiveMachine = getNextLiveMachine();
					IDistributedHashTable dhtNextLiveMachine = (IDistributedHashTable) 
							Naming.lookup("rmi://localhost:"+ nextLiveMachine.getValue() +"/DistributedHashTable");
					Map.Entry<Integer, String> nextRepMachineAddress = dhtNextLiveMachine.getRepHostAddress(myId, myId);
					boolean isDirty = true;
					if(nextRepMachineAddress != null){
						handleMessage("onServerJoin: machine " + myId + " - other replication server " + nextRepMachineAddress.getKey() + " is online");
						isDirty = false;
					}
					else
						handleMessage("onServerJoin: machine " + myId + " - other replication storage of server " + repServer.getId() + " is offline");
					
					IDistributedHashTable dhtJointMachine = (IDistributedHashTable) 
							Naming.lookup("rmi://localhost:"+ onlineServerAddress +"/DistributedHashTable");
					
			        // update dirty insert cache on the server that joins to the ring
			        if(repServer.getDirtyInsertCache().size() > 0 &&
			        		dhtJointMachine.syncDirtyInsertCache(myId , repServer.getDirtyInsertCache(), isDirty)){
			        	// delete dirty inserts as master server gets the updates and the other replication is online
			        	if(!isDirty)
			        		repServer.clearDirtyInsert();
			        }
			        // update dirty delete cache on the server that joins to the ring 
			        if(repServer.getDirtyDeleteCache().size() > 0 &&
			        		dhtJointMachine.syncDirtyDeleteCache(myId, repServer.getDirtyDeleteCache(), isDirty)){
			        	// delete dirty deletes as master server gets the updates and the other replication is online
			        	if(!isDirty)
			        		repServer.clearDirtyDelete();
			        }
					return null;
				}
			};
			worker.execute();
		} catch (Exception e1) {
			handleMessage("Error-onServerJoin: machine " + this.myId + " - server" + joinServerId + " failed to update dirty updates " + e1.getMessage()); 
		}
	}