All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.roboconf.dm.internal.api.impl.RandomMngrImpl Maven / Gradle / Ivy

There is a newer version: 0.9.1
Show newest version
/**
 * Copyright 2015-2016 Linagora, Université Joseph Fourier, Floralis
 *
 * The present code is developed in the scope of the joint LINAGORA -
 * Université Joseph Fourier - Floralis research program and is designated
 * as a "Result" pursuant to the terms and conditions of the LINAGORA
 * - Université Joseph Fourier - Floralis research program. Each copyright
 * holder of Results enumerated here above fully & independently holds complete
 * ownership of the complete Intellectual Property rights applicable to the whole
 * of said Results, and may freely exploit it in any manner which does not infringe
 * the moral rights of the other copyright holders.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.roboconf.dm.internal.api.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Logger;

import net.roboconf.core.model.beans.Application;
import net.roboconf.core.model.beans.ExportedVariable;
import net.roboconf.core.model.beans.ExportedVariable.RandomKind;
import net.roboconf.core.model.beans.Instance;
import net.roboconf.core.model.helpers.InstanceHelpers;
import net.roboconf.core.utils.Utils;
import net.roboconf.dm.internal.api.IRandomMngr;
import net.roboconf.dm.internal.api.impl.beans.InstanceContext;
import net.roboconf.dm.internal.utils.ConfigurationUtils;
import net.roboconf.dm.management.api.IPreferencesMngr;

/**
 * @author Vincent Zurczak - Linagora
 */
public class RandomMngrImpl implements IRandomMngr {

	/**
	 * A map that associates AGENTS and random ports.
	 * 

* An agent is identified by an application and a scoped instance. *

*/ final Map> agentToRandomPorts = new HashMap<> (); private final Logger logger = Logger.getLogger( getClass().getName()); private final IPreferencesMngr preferencesMngr; /** * Constructor. * @param preferencesMngr */ public RandomMngrImpl( IPreferencesMngr preferencesMngr ) { this.preferencesMngr = preferencesMngr; } @Override public synchronized void generateRandomValues( Application application, Instance instance ) { // Exported variables that are random will be set a value for( ExportedVariable var : instance.getComponent().exportedVariables.values()) { // Not random? if( ! var.isRandom()) continue; // Port if( var.getRandomKind() == RandomKind.PORT ) { // Acknowledge: verify a random value was not already set on it. // Otherwise, generate a random port and associate it. if( ! acknowledgePort( application, instance, var.getName())) generateRandomPort( application, instance, var.getName()); } } // Save the updated model ConfigurationUtils.saveInstances( application ); } @Override public void generateAllRandomValues( Application application ) { for( Instance instance : InstanceHelpers.getAllInstances( application )) { generateRandomValues( application, instance ); } } @Override public synchronized void releaseRandomValues( Application application, Instance instance ) { // Only used for random ports. // We only remove the ports used by this instance. List portsToRelease = new ArrayList<> (); for( ExportedVariable var : instance.getComponent().exportedVariables.values()) { if( ! var.isRandom() || var.getRandomKind() != RandomKind.PORT ) continue; String value = instance.overriddenExports.get( var.getName()); if( value != null ) portsToRelease.add( Integer.parseInt( value )); } // Update the cache InstanceContext ctx = findAgentContext( application, instance ); List ports = this.agentToRandomPorts.get( ctx ); if( ports != null ) { ports.removeAll( portsToRelease ); if( ports.isEmpty()) this.agentToRandomPorts.remove( ctx ); } } @Override public void releaseAllRandomValues( Application application ) { // Only used for random ports. // Find the contexts to remove List toRemove = new ArrayList<> (); for( InstanceContext ctx : this.agentToRandomPorts.keySet()) { if( ctx.getQualifier() == null && Objects.equals( application.getName(), ctx.getName())) toRemove.add( ctx ); } // Remove them for( InstanceContext ctx : toRemove ) this.agentToRandomPorts.remove( ctx ); } @Override public void restoreRandomValuesCache( Application application ) { // Only used for random ports. for( Instance instance : InstanceHelpers.getAllInstances( application )) { // Restore ALL the variables List variablesToRegenerate = new ArrayList<> (); for( ExportedVariable var : instance.getComponent().exportedVariables.values()) { // We only care about random ports if( ! var.isRandom() || var.getRandomKind() != RandomKind.PORT ) continue; // Find the overridden value. // If it exists, restore it. String value = instance.overriddenExports.get( var.getName()); if( value != null && ! acknowledgePort( application, instance, var.getName())) variablesToRegenerate.add( var ); } // Restoration may have failed for some. Regenerate new ports for( ExportedVariable var : variablesToRegenerate ) { this.logger.warning( "Generating a new random port for " + var.getName() + " in instance " + instance + " of " + application ); generateRandomPort( application, instance, var.getName()); } // Save the updated model? if( ! variablesToRegenerate.isEmpty()) ConfigurationUtils.saveInstances( application ); } } // Port Management private static final int PORT_MIN = 10000; private static final int PORT_MAX = 65500; /** * Picks up port among the available ones in the allowed range (> 9999). *

* Once picked up, it is set as an overridden export on the instance. * This method should be called only when {@link #acknowledgePort(Application, Instance, String)} * returned false. *

* * @param application the application * @param instance the instance * @param exportedVariableName the name of the exported variable */ private void generateRandomPort( Application application, Instance instance, String exportedVariableName ) { List forbiddenPorts = new ArrayList<> (); // Forbidden ports specified in the preferences String preferences = this.preferencesMngr.get( IPreferencesMngr.FORBIDDEN_RANDOM_PORTS, "" ); for( String s : Utils.splitNicely( preferences, "," )) { if( Utils.isEmptyOrWhitespaces( s )) continue; try { forbiddenPorts.add( Integer.parseInt( s )); } catch( NumberFormatException e ) { this.logger.severe( "An invalid port was found in the preferences: " + s ); } } // Ports already in use InstanceContext ctx = findAgentContext( application, instance ); List portsUsedByAgent = this.agentToRandomPorts.get( ctx ); if( portsUsedByAgent != null ) forbiddenPorts.addAll( portsUsedByAgent ); // Now, pick up a random port Integer randomPort = -1; for( int i=PORT_MIN; i associatedPorts = this.agentToRandomPorts.get( newCtx ); if( associatedPorts == null ) { associatedPorts = new ArrayList (); this.agentToRandomPorts.put( newCtx, associatedPorts ); } associatedPorts.add( randomPort ); // Inject the variable value in the model. // Note: we could edit the graph variable directly. // But that would be bad, since several instances of the same component may have different ports. So, // we cannot put the information in the component. Instead, we put it as an overridden export. instance.overriddenExports.put( exportedVariableName, String.valueOf( randomPort )); } /** * If the instance already has a value (overridden export) for a random variable, then use it. *

* Basically, we do not have to define an overridden export. * We only have to update the cache to not pick up the same port later. *

* * @param application the application * @param instance the instance * @param exportedVariableName the name of the exported variable * @return */ private boolean acknowledgePort( Application application, Instance instance, String exportedVariableName ) { boolean acknowledged = false; String value = instance.overriddenExports.get( exportedVariableName ); if( value != null ) { // If there is an overridden value, use it this.logger.fine( "Acknowledging random port value for " + exportedVariableName + " in instance " + instance + " of " + application ); Integer portValue = Integer.parseInt( value ); InstanceContext ctx = findAgentContext( application, instance ); List associatedPorts = this.agentToRandomPorts.get( ctx ); if( associatedPorts == null ) { associatedPorts = new ArrayList (); this.agentToRandomPorts.put( ctx, associatedPorts ); } // Verify it is not already used. // And cache it so that we do not pick it up later. if( associatedPorts.contains( portValue )) { this.logger.warning( "Random port already used! Failed to acknowledge/restore " + exportedVariableName + " in instance " + instance + " of " + application ); acknowledged = false; } else { associatedPorts.add( portValue ); acknowledged = true; } } return acknowledged; } // Miscellaneous /** * Builds an instance context corresponding to an agent. * @param application an application * @param instance an instance * @return an instance context made up of the application and the right scoped instance */ private InstanceContext findAgentContext( Application application, Instance instance ) { Instance scopedInstance = InstanceHelpers.findScopedInstance( instance ); return new InstanceContext( application, scopedInstance ); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy