/** * Finds the root instance for an instance. * @param instance an instance (not null) * @return a non-null instance, the root instance */ public static Instance findRootInstance( Instance instance ) { Instance rootInstance = instance; while( rootInstance.getParent() != null ) rootInstance = rootInstance.getParent(); return rootInstance; }
/** * Finds the scoped instance for an instance (i.e. the agent that manages this instance). * @param instance an instance (not null) * @return a non-null instance, the scoped instance */ public static Instance findScopedInstance( Instance instance ) { Instance scopedInstance = instance; while( scopedInstance.getParent() != null && ! isTarget( scopedInstance )) scopedInstance = scopedInstance.getParent(); return scopedInstance; }
/** * Builds a string representing the path from a root instance to this instance. * <p> * This string can be considered as a computed ID (or signature) of the instance. * It only makes sense within a given application. * </p> * * @param inst an instance (not null) * @return a string (not null) */ public static String computeInstancePath( Instance inst ) { StringBuilder sb = new StringBuilder(); for( Instance current = inst; current != null; current = current.getParent()) { StringBuilder currentSb = new StringBuilder( "/" ); if( ! Utils.isEmptyOrWhitespaces( current.getName())) currentSb.append( current.getName()); sb.insert( 0, currentSb.toString()); } return sb.toString(); }
/** * Constructor. * @param instance */ public MsgCmdAddInstance( Instance instance ) { this.parentInstancePath = instance.getParent() == null ? null : InstanceHelpers.computeInstancePath( instance.getParent()); this.instanceName = instance.getName(); this.componentName = instance.getComponent() != null ? instance.getComponent().getName() : null; this.channels = instance.channels; this.data = instance.data; this.overridenExports = instance.overriddenExports; }
/** * Removes children instances which are off-scope. * <p> * Agents manage all the instances under their scoped instance, except those * that are associated with the "target" installer. Such instances are indeed managed by another agent. * </p> * * @param scopedInstance a scoped instance */ public static void removeOffScopeInstances( Instance scopedInstance ) { List<Instance> todo = new ArrayList<> (); todo.addAll( scopedInstance.getChildren()); while( ! todo.isEmpty()) { Instance current = todo.remove( 0 ); if( isTarget( current )) current.getParent().getChildren().remove( current ); else todo.addAll( current.getChildren()); } }
/** * Constructor. * @param instance */ public MsgCmdAddInstance( Instance instance ) { this.parentInstancePath = instance.getParent() == null ? null : InstanceHelpers.computeInstancePath( instance.getParent()); this.instanceName = instance.getName(); this.componentName = instance.getComponent() != null ? instance.getComponent().getName() : null; this.channels = instance.channels; this.data = instance.data; this.overridenExports = instance.overriddenExports; }
private void processMsgNotifInstanceRemoved( MsgNotifInstanceRemoved message ) { String instancePath = message.getInstancePath(); Application app = this.manager.applicationMngr().findApplicationByName( message.getApplicationName()); Instance instance = InstanceHelpers.findInstanceByPath( app, instancePath ); // If 'app' is null, then 'instance' is also null. if( instance == null ) { StringBuilder sb = new StringBuilder(); sb.append( "A 'REMOVE' notification was received for an unknown instance: " ); sb.append( instancePath ); sb.append( " (app = " ); sb.append( app ); sb.append( ")." ); this.logger.warning( sb.toString()); } else { if( InstanceHelpers.isTarget( instance )) this.logger.warning( "Anormal behavior. A 'REMOVE' notification was received for a scoped instance: " + instancePath + "." ); else instance.getParent().getChildren().remove( instance ); this.logger.info( "Instance " + instancePath + " was removed from the model." ); } }
private Collection<Instance> replicateInstancesFrom( Instance rootInstance ) { Collection<Instance> newRootInstances = new ArrayList<> (); // Begin with the duplicates of the deepest instances. List<Instance> orderedInstances = InstanceHelpers.buildHierarchicalList( rootInstance ); Collections.reverse( orderedInstances ); for( Instance instance : orderedInstances ) { String countAsString = instance.data.remove( INST_COUNT ); Integer count = 1; try { count = Integer.parseInt( countAsString ); } catch( NumberFormatException e ) { // ignore, the validator for the parsing model should handle this } if( count <= 1 ) continue; String format = "%0" + String.valueOf( count ).length() + "d"; for( int i=2; i<=count; i++ ) { Instance copy = InstanceHelpers.replicateInstance( instance ); copy.name( copy.getName() + String.format( format, i )); if( instance.getParent() != null ) InstanceHelpers.insertChild( instance.getParent(), copy ); else newRootInstances.add( copy ); } // Update the first one instance.name( instance.getName() + String.format( format, 1 )); } return newRootInstances; }
instanceToDuplicate.put( current, copy ); Instance parent = instanceToDuplicate.get( current.getParent()); if( parent != null ) insertChild( parent, copy );
this.logger.fine( instancePath + " cannot be deployed. Prerequisite status: NOT_DEPLOYED (but was " + instance.getStatus() + ")." ); } else if( instance.getParent() != null && instance.getParent().getStatus() != InstanceStatus.DEPLOYED_STARTED && instance.getParent().getStatus() != InstanceStatus.DEPLOYED_STOPPED && instance.getParent().getStatus() != InstanceStatus.UNRESOLVED && instance.getParent().getStatus() != InstanceStatus.WAITING_FOR_ANCESTOR ) { this.logger.fine( instancePath + " cannot be deployed because its parent is not deployed. Parent status: " + instance.getParent().getStatus() + "." );
this.logger.fine( instancePath + " cannot be started. Prerequisite status: DEPLOYED_STOPPED or WAITING_FOR_ANCESTOR (but was " + instance.getStatus() + ")." ); } else if( instance.getParent() != null && instance.getParent().getStatus() != InstanceStatus.DEPLOYED_STARTED ) { this.logger.fine( instancePath + " cannot be started because its parent is not started. Parent status: " + instance.getParent().getStatus() + "." ); if( instance.getParent().getStatus() == InstanceStatus.UNRESOLVED || instance.getParent().getStatus() == InstanceStatus.WAITING_FOR_ANCESTOR ) {
/** * Removes an instance to the local model. * @param msg the message to process * @throws IOException if an error occurred with the messaging */ void processMsgRemoveInstance( MsgCmdRemoveInstance msg ) throws IOException { // Remove the instance boolean removed = false; Instance instance = InstanceHelpers.findInstanceByPath( this.scopedInstance, msg.getInstancePath()); if( instance == null ) { this.logger.severe( "No instance matched " + msg.getInstancePath() + " on the agent. Request to remove it from the model is dropped." ); } else if( instance.getStatus() != InstanceStatus.NOT_DEPLOYED ) { this.logger.severe( "Instance " + msg.getInstancePath() + " cannot be removed. Instance status: " + instance.getStatus() + "." ); // We do not have to check children's status. // We cannot have a parent in NOT_DEPLOYED and a child in STARTED (as an example). } else if( instance.getParent() != null ) { removed = true; instance.getParent().getChildren().remove( instance ); this.logger.fine( "Child instance " + msg.getInstancePath() + " was removed from the model." ); } else { this.logger.fine( "The root instance " + msg.getInstancePath() + " cannot be removed. The agent must be reboot and/or reconfigured." ); } // Configure the messaging if( removed ) { this.messagingClient.sendMessageToTheDm( new MsgNotifInstanceRemoved( this.agent.getApplicationName(), instance )); for( Instance instanceToProcess : InstanceHelpers.buildHierarchicalList( instance )) this.messagingClient.listenToExportsFromOtherAgents( ListenerCommand.STOP, instanceToProcess ); } }
/** * Deploys an instance. * @param msg the message to process * @throws IOException if an error occurred with the messaging or while manipulating the file system * @throws PluginException if something went wrong with the plug-in */ void processMsgChangeInstanceState( MsgCmdChangeInstanceState msg ) throws IOException, PluginException { PluginInterface plugin; Instance instance = InstanceHelpers.findInstanceByPath( this.scopedInstance, msg.getInstancePath()); if( instance == null ) this.logger.severe( "No instance matched " + msg.getInstancePath() + " on the agent. Request to deploy it is dropped." ); else if( instance.getParent() == null ) this.logger.severe( "No action on the root instance is permitted." ); else if(( plugin = this.agent.findPlugin( instance )) == null ) this.logger.severe( "No plug-in was found to deploy " + msg.getInstancePath() + "." ); else AbstractLifeCycleManager .build( instance, this.agent.getApplicationName(), this.messagingClient) .changeInstanceState( instance, plugin, msg.getNewState(), msg.getFileNameToFileContent()); }
/** * Starts children instances when they are waiting for their ancestors to start. * <p> * To invoke every time imports change. * </p> * @throws IOException if something went wrong * @throws PluginException if something went wrong */ private void startChildrenInstancesWaitingForAncestors() throws IOException, PluginException { List<Instance> childrenInstances = InstanceHelpers.buildHierarchicalList( this.scopedInstance ); childrenInstances.remove( this.scopedInstance ); for( Instance childInstance : childrenInstances ) { if( childInstance.getStatus() != InstanceStatus.WAITING_FOR_ANCESTOR ) continue; if( childInstance.getParent().getStatus() != InstanceStatus.DEPLOYED_STARTED ) continue; PluginInterface plugin = this.agent.findPlugin( childInstance ); if( plugin == null ) this.logger.severe( "No plug-in was found for " + InstanceHelpers.computeInstancePath( childInstance ) + "." ); else AbstractLifeCycleManager .build( childInstance, this.agent.getApplicationName(), this.messagingClient) .changeInstanceState( childInstance, plugin, InstanceStatus.DEPLOYED_STARTED, null ); } } }
@Test public void testInsertChild() { Instance instance_1 = new Instance( "inst 1" ); Instance instance_1_1 = new Instance( "inst 11" ); Assert.assertNull( instance_1.getParent()); Assert.assertNull( instance_1_1.getParent()); Assert.assertEquals( 0, instance_1.getChildren().size()); InstanceHelpers.insertChild( instance_1, instance_1_1 ); Assert.assertEquals( 1, instance_1.getChildren().size()); Assert.assertEquals( instance_1_1, instance_1.getChildren().iterator().next()); Assert.assertEquals( instance_1, instance_1_1.getParent()); Assert.assertTrue( instance_1.getChildren().contains( instance_1_1 )); Assert.assertNull( instance_1.getParent()); Assert.assertNotSame( instance_1, instance_1_1 ); }
@Test public void testChain() { Instance inst = new Instance().name( "ins" ).status( InstanceStatus.DEPLOYING ).component( null ).parent( null ); Assert.assertEquals( 0, inst.channels.size()); Assert.assertEquals( "ins", inst.getName()); Assert.assertEquals( InstanceStatus.DEPLOYING, inst.getStatus()); Assert.assertNull( inst.getComponent()); Assert.assertNull( inst.getParent()); Assert.assertEquals( 1, inst.channel( "woo" ).channels.size()); Assert.assertEquals( 2, inst.channel( "yeah" ).channels.size()); Assert.assertEquals( 2, inst.channel( "woo" ).channels.size()); }
Assert.assertEquals( original_1.getComponent(), copy.getComponent()); Assert.assertEquals( 2, copy.getChildren().size()); Assert.assertNull( copy.getParent()); Assert.assertEquals( original_2.getComponent(), children[ 0 ].getComponent()); Assert.assertEquals( 1, children[ 0 ].getChildren().size()); Assert.assertEquals( copy, children[ 0 ].getParent()); Assert.assertEquals( original_22.getComponent(), children[ 1 ].getComponent()); Assert.assertEquals( 0, children[ 1 ].getChildren().size()); Assert.assertEquals( copy, children[ 1 ].getParent()); Assert.assertEquals( original_3.getComponent(), lastChild.getComponent()); Assert.assertEquals( 0, lastChild.getChildren().size()); Assert.assertEquals( children[ 0 ], lastChild.getParent()); Assert.assertEquals( original_2.getComponent(), copy.getComponent()); Assert.assertEquals( 1, copy.getChildren().size()); Assert.assertNull( copy.getParent()); Assert.assertNotNull( original_2.getParent()); Assert.assertEquals( original_3.getComponent(), lastChild.getComponent()); Assert.assertEquals( 0, lastChild.getChildren().size()); Assert.assertEquals( copy, lastChild.getParent());
@Test public void checkInstanceReplication() { TestApplicationTemplate tpl = new TestApplicationTemplate(); Application app = new Application( tpl ); Assert.assertEquals( 5, InstanceHelpers.getAllInstances( app ).size()); Assert.assertEquals( 5, InstanceHelpers.getAllInstances( tpl ).size()); for( Instance inst : InstanceHelpers.getAllInstances( tpl )) { String instancePath = InstanceHelpers.computeInstancePath( inst ); Instance copiedInstance = InstanceHelpers.findInstanceByPath( app, instancePath ); Assert.assertNotNull( copiedInstance ); Assert.assertEquals( inst.getName(), copiedInstance.getName()); Assert.assertEquals( inst.getComponent(), copiedInstance.getComponent()); Assert.assertEquals( inst.getImports(), copiedInstance.getImports()); Assert.assertEquals( inst.getParent(), copiedInstance.getParent()); Assert.assertEquals( inst.getChildren().size(), copiedInstance.getChildren().size()); // Paths are the same, so the children are equal (even if they are not the same object) Assert.assertEquals( inst.getChildren(), copiedInstance.getChildren()); Assert.assertEquals( inst.channels, copiedInstance.channels ); Assert.assertEquals( inst.overriddenExports, copiedInstance.overriddenExports ); Assert.assertEquals( inst.data, copiedInstance.data ); Assert.assertFalse( inst == copiedInstance ); } }