/** * Join the federation of the given name. This will find the channel with the same name as the * federation and connect to it. It will then attempt to mark this execution as a federate within * that channel (as opposed to just a regular member). * * <p>== Federate Names == A federation can optionally require that each federate have a unique * name (RID option). If this is not the case, Portico will always ensure that federates do have * unique names by modifying newly joining duplicates. If unique names are enforced and we try to * join with an existing name, an exception is thrown. * * <p>== FOM Modules == If there are additional FOM modules, we attempt a dry-run merge first to * identify any issues. Should that be successful, we join and then apply the changes to our local * copy of the FOM. The Role Call semantics that executes outside of the connection after we join * handles the job of dispersing the new module information to everyone else (who then also apply * them locally). */ public ConnectedRoster joinFederation(JoinFederation joinMessage) throws Exception { // connect to the federation channel if we are not already Federation federation = findFederation(joinMessage.getFederationName()); // validate that our FOM modules can be merged successfully with the existing FOM first logger.debug( "Validate that [" + joinMessage.getJoinModules().size() + "] modules can merge successfully with the existing FOM"); ModelMerger.mergeDryRun(federation.getManifest().getFom(), joinMessage.getJoinModules()); logger.debug("Modules can be merged successfully, continue with join"); // tell the channel that we're joining the federation String joinedName = federation.sendJoinFederation(joinMessage.getFederateName(), this.lrc); // the joined name could be different from what we asked for, so update the request // to make sure it is correct joinMessage.setFederateName(joinedName); // now that we've joined a federation, store it here so we can route messages to it this.joinedFederation = federation; // We have to merge the FOMs together here before we return to the Join handler and // a RoleCall is sent out. We do this because although we receive our own RoleCall // notice (with the additional modules) we won't process it as we can't tell if it's // one we sent out because we joined (and thus need to merge) or because someone else // joined. Additional modules will only be present if it is a new join, so // we could figure it out that way, but that will cause redundant merges for the JVM // binding (as all connections share the same object model reference). To cater to the // specifics of this connection it's better to put the logic in the connection rather than // in the generic-to-all-connections RoleCallHandler. Long way of saying we need to merge // in the additional join modules that were provided here. F*** IT! WE'LL DO IT LIVE! if (joinMessage.getJoinModules().size() > 0) { logger.debug( "Merging " + joinMessage.getJoinModules().size() + " additional FOM modules that we receive with join request"); ObjectModel fom = federation.getManifest().getFom(); fom.unlock(); federation.getManifest().setFom(ModelMerger.merge(fom, joinMessage.getJoinModules())); fom.lock(); } // create and return the roster return new Roster( federation.getManifest().getLocalFederateHandle(), federation.getManifest().getFederateHandles(), federation.getManifest().getFom()); }
/** * Resign ourselves from the federation we are currently connected to. This will not disconnect us * from the channel, but will rather just mark us as no longer being a federate (only a channel * member). * * <p>An exception is thrown if any of the checks we run (such as whether we are infact even * connected to a federation at all!) fail. */ public void resignFederation(ResignFederation resignMessage) throws Exception { // make sure we're joined to the federation if (joinedFederation == null || joinedFederation.getManifest().isLocalFederateJoined() == false) { throw new JFederateNotExecutionMember( "Federate [" + resignMessage.getFederateName() + "] not joined to [" + resignMessage.getFederationName() + "]"); } // send out the resign notification joinedFederation.sendResignFederation(resignMessage); // all happy, as we're no longer joined, set out joined channel to null joinedFederation = null; }