
net.roboconf.dm.internal.api.impl.ApplicationMngrImpl Maven / Gradle / Ivy
/**
* 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.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import net.roboconf.core.Constants;
import net.roboconf.core.ErrorCode;
import net.roboconf.core.RoboconfError;
import net.roboconf.core.model.ApplicationDescriptor;
import net.roboconf.core.model.RuntimeModelIo.InstancesLoadResult;
import net.roboconf.core.model.beans.Application;
import net.roboconf.core.model.beans.ApplicationTemplate;
import net.roboconf.core.model.beans.Instance;
import net.roboconf.core.model.beans.Instance.InstanceStatus;
import net.roboconf.core.model.helpers.InstanceHelpers;
import net.roboconf.core.model.helpers.RoboconfErrorHelpers;
import net.roboconf.core.utils.Utils;
import net.roboconf.dm.internal.api.IRandomMngr;
import net.roboconf.dm.internal.utils.ConfigurationUtils;
import net.roboconf.dm.management.ManagedApplication;
import net.roboconf.dm.management.api.IApplicationMngr;
import net.roboconf.dm.management.api.IApplicationTemplateMngr;
import net.roboconf.dm.management.api.IAutonomicMngr;
import net.roboconf.dm.management.api.IConfigurationMngr;
import net.roboconf.dm.management.api.IMessagingMngr;
import net.roboconf.dm.management.api.INotificationMngr;
import net.roboconf.dm.management.api.ITargetsMngr;
import net.roboconf.dm.management.events.EventType;
import net.roboconf.dm.management.exceptions.AlreadyExistingException;
import net.roboconf.dm.management.exceptions.InvalidApplicationException;
import net.roboconf.dm.management.exceptions.UnauthorizedActionException;
import net.roboconf.messaging.api.business.ListenerCommand;
import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdChangeBinding;
/**
* @author Noël - LIG
* @author Pierre-Yves Gibello - Linagora
* @author Vincent Zurczak - Linagora
* @author Pierre Bourret - Université Joseph Fourier
*/
public class ApplicationMngrImpl implements IApplicationMngr {
private final Logger logger = Logger.getLogger( getClass().getName());
private final Map nameToManagedApplication;
private final INotificationMngr notificationMngr;
private final IConfigurationMngr configurationMngr;
private final ITargetsMngr targetsMngr;
private final IMessagingMngr messagingMngr;
private final IRandomMngr randomMngr;
private final IAutonomicMngr autonomicMngr;
private IApplicationTemplateMngr applicationTemplateMngr;
/**
* Constructor.
* @param notificationMngr
* @param configurationMngr
* @param messagingMngr
* @param targetsMngr
* @param randomMngr
*/
public ApplicationMngrImpl(
INotificationMngr notificationMngr,
IConfigurationMngr configurationMngr,
ITargetsMngr targetsMngr,
IMessagingMngr messagingMngr,
IRandomMngr randomMngr,
IAutonomicMngr autonomicMngr ) {
this.nameToManagedApplication = new ConcurrentHashMap ();
this.notificationMngr = notificationMngr;
this.configurationMngr = configurationMngr;
this.messagingMngr = messagingMngr;
this.targetsMngr = targetsMngr;
this.randomMngr = randomMngr;
this.autonomicMngr = autonomicMngr;
}
/**
* @param applicationTemplateMngr the applicationTemplateMngr to set
*/
public void setApplicationTemplateMngr( IApplicationTemplateMngr applicationTemplateMngr ) {
this.applicationTemplateMngr = applicationTemplateMngr;
}
@Override
public Application findApplicationByName( String applicationName ) {
ManagedApplication ma = this.nameToManagedApplication.get( applicationName );
return ma != null ? ma.getApplication() : null;
}
@Override
public ManagedApplication findManagedApplicationByName( String applicationName ) {
return this.nameToManagedApplication.get( applicationName );
}
@Override
public Collection getManagedApplications() {
return this.nameToManagedApplication.values();
}
@Override
public ManagedApplication createApplication( String name, String description, String tplName, String tplQualifier )
throws IOException, AlreadyExistingException, InvalidApplicationException {
// Always verify the configuration first
this.messagingMngr.checkMessagingConfiguration();
// Create the application
ApplicationTemplate tpl = this.applicationTemplateMngr.findTemplate( tplName, tplQualifier );
if( tpl == null )
throw new InvalidApplicationException( new RoboconfError( ErrorCode.PROJ_APPLICATION_TEMPLATE_NOT_FOUND ));
return createApplication( name, description, tpl );
}
@Override
public ManagedApplication createApplication( String name, String description, ApplicationTemplate tpl )
throws IOException, AlreadyExistingException {
// Always verify the configuration first
this.messagingMngr.checkMessagingConfiguration();
// Create the application
ManagedApplication ma = createNewApplication( name, description, tpl, this.configurationMngr.getWorkingDirectory());
// Copy the target settings, if any
this.targetsMngr.copyOriginalMapping( ma.getApplication());
// Set a value to random variables, if any
this.randomMngr.generateAllRandomValues( ma.getApplication());
// Start listening to messages
this.messagingMngr.getMessagingClient().listenToAgentMessages( ma.getApplication(), ListenerCommand.START );
// Notify listeners
this.notificationMngr.application( ma.getApplication(), EventType.CREATED );
// Load autonomic rules
this.autonomicMngr.loadApplicationRules( ma.getApplication());
this.logger.fine( "Application " + ma.getApplication().getName() + " was successfully loaded and added." );
return ma;
}
@Override
public void updateApplication( ManagedApplication ma, String newDesc ) throws IOException {
// Basic checks
this.messagingMngr.checkMessagingConfiguration();
// Update it
Application app = ma.getApplication();
app.setDescription( newDesc );
File targetDirectory = app.getDirectory();
File descFile = new File( targetDirectory, Constants.PROJECT_DIR_DESC + "/" + Constants.PROJECT_FILE_DESCRIPTOR );
Utils.createDirectory( descFile.getParentFile());
ApplicationDescriptor.save( descFile, app );
// Notify listeners
this.notificationMngr.application( ma.getApplication(), EventType.CHANGED );
this.logger.fine( "The description of application " + ma.getApplication().getName() + " was successfully updated." );
}
@Override
public void deleteApplication( ManagedApplication ma )
throws UnauthorizedActionException, IOException {
// What really matters is that there is no agent running.
// If all the root instances are not deployed, then nothing is deployed at all.
String applicationName = ma.getApplication().getName();
for( Instance rootInstance : ma.getApplication().getRootInstances()) {
if( rootInstance.getStatus() != InstanceStatus.NOT_DEPLOYED )
throw new UnauthorizedActionException( applicationName + " contains instances that are still deployed." );
}
// Stop listening to messages first
try {
this.messagingMngr.checkMessagingConfiguration();
this.messagingMngr.getMessagingClient().listenToAgentMessages( ma.getApplication(), ListenerCommand.STOP );
this.messagingMngr.getMessagingClient().deleteMessagingServerArtifacts( ma.getApplication());
} catch( IOException e ) {
Utils.logException( this.logger, e );
}
// Release random variables, if any
this.randomMngr.releaseAllRandomValues( ma.getApplication());
// Notify listeners
this.notificationMngr.application( ma.getApplication(), EventType.DELETED );
// Remove it from the targets
Application app = ma.getApplication();
this.targetsMngr.applicationWasDeleted( app );
// Remove the autonomic context
this.autonomicMngr.unloadApplicationRules( app );
// Delete artifacts
this.logger.info( "Deleting the application called " + app.getName() + "..." );
this.nameToManagedApplication.remove( app.getName());
app.removeAssociationWithTemplate();
File targetDirectory = ConfigurationUtils.findApplicationDirectory( app.getName(), this.configurationMngr.getWorkingDirectory());
Utils.deleteFilesRecursively( targetDirectory );
this.logger.info( "Application " + app.getName() + " was successfully deleted." );
}
@Override
public void restoreApplications() {
File configurationDirectory = this.configurationMngr.getWorkingDirectory();
this.logger.info( "Restoring applications from " + configurationDirectory + "..." );
this.nameToManagedApplication.clear();
File templatesDirectory = new File( configurationDirectory, ConfigurationUtils.APPLICATIONS );
for( File dir : Utils.listDirectories( templatesDirectory )) {
try {
// Read the descriptor
File descriptorFile = new File( dir, Constants.PROJECT_DIR_DESC + "/" + Constants.PROJECT_FILE_DESCRIPTOR );
ApplicationDescriptor desc = ApplicationDescriptor.load( descriptorFile );
ApplicationTemplate tpl = this.applicationTemplateMngr.findTemplate( desc.getTemplateName(), desc.getTemplateQualifier());
if( tpl == null )
throw new InvalidApplicationException( new RoboconfError( ErrorCode.PROJ_APPLICATION_TEMPLATE_NOT_FOUND ));
// Recreate the application
if( this.nameToManagedApplication.containsKey( desc.getName()))
throw new AlreadyExistingException( desc.getName());
Application app = new Application( desc.getName(), tpl ).description( desc.getDescription());
File targetDirectory = ConfigurationUtils.findApplicationDirectory( app.getName(), configurationDirectory );
app.setDirectory( targetDirectory );
ManagedApplication ma = new ManagedApplication( app );
this.nameToManagedApplication.put( ma.getName(), ma );
// Restore the cache for random generation in variables
this.randomMngr.restoreRandomValuesCache( app );
// Start listening to messages
this.messagingMngr.getMessagingClient().listenToAgentMessages( ma.getApplication(), ListenerCommand.START );
// Read application bindings.
ConfigurationUtils.loadApplicationBindings( app );
// Load autonomic rules
this.autonomicMngr.loadApplicationRules( app );
// Restore the instances
InstancesLoadResult ilr = ConfigurationUtils.restoreInstances( ma );
checkErrors( ilr.getLoadErrors(), this.logger );
ma.getApplication().getRootInstances().clear();
ma.getApplication().getRootInstances().addAll( ilr.getRootInstances());
} catch( AlreadyExistingException | InvalidApplicationException | IOException e ) {
this.logger.warning( "Application restoration failed for directory " + dir + " (" + e.getClass().getSimpleName() + ")." );
Utils.logException( this.logger, e );
}
}
this.logger.info( "Applications restoration from " + configurationDirectory + " has just completed." );
}
@Override
public boolean isTemplateUsed( ApplicationTemplate tpl ) {
boolean result = false;
for( ManagedApplication ma : this.nameToManagedApplication.values()) {
if( tpl.equals( ma.getApplication().getTemplate())) {
result = true;
break;
}
}
return result;
}
/**
* A method to check errors.
* @param errors a non-null list of errors
* @param logger a logger
* @throws InvalidApplicationException if there are critical errors
*/
static void checkErrors( Collection errors, Logger logger )
throws InvalidApplicationException {
if( RoboconfErrorHelpers.containsCriticalErrors( errors ))
throw new InvalidApplicationException( errors );
for( String warning : RoboconfErrorHelpers.extractAndFormatWarnings( errors ))
logger.warning( warning );
}
/**
* Creates a new application from a template.
* @param name the application's name
* @param description the application's description
* @param tpl the application's template
* @param configurationDirectory the DM's configuration directory
* @return a new managed application
* @throws AlreadyExistingException if an application with this name already exists
* @throws IOException if the application's directory could not be created
*/
private ManagedApplication createNewApplication(
String name,
String description,
ApplicationTemplate tpl,
File configurationDirectory )
throws AlreadyExistingException, IOException {
this.logger.info( "Creating application " + name + " from template " + tpl + "..." );
if( Utils.isEmptyOrWhitespaces( name ))
throw new IOException( "An application name cannot be empty." );
if( this.nameToManagedApplication.containsKey( name ))
throw new AlreadyExistingException( name );
// Create the application's directory
Application app = new Application( name, tpl ).description( description );
File targetDirectory = ConfigurationUtils.findApplicationDirectory( app.getName(), configurationDirectory );
Utils.createDirectory( targetDirectory );
app.setDirectory( targetDirectory );
// Create a descriptor
File descFile = new File( targetDirectory, Constants.PROJECT_DIR_DESC + "/" + Constants.PROJECT_FILE_DESCRIPTOR );
Utils.createDirectory( descFile.getParentFile());
ApplicationDescriptor.save( descFile, app );
// Copy all the templates's directories, except the descriptor, graph and instances
List tplDirectories = Utils.listDirectories( tpl.getDirectory());
List toSkip = Arrays.asList( Constants.PROJECT_DIR_DESC, Constants.PROJECT_DIR_GRAPH, Constants.PROJECT_DIR_INSTANCES );
for( File dir : tplDirectories ) {
if( toSkip.contains( dir.getName().toLowerCase()))
continue;
File newDir = new File( targetDirectory, dir.getName());
Utils.copyDirectory( dir, newDir );
}
// Update the application name in all the root instances
for( Instance rootInstance : app.getRootInstances())
rootInstance.data.put( Instance.APPLICATION_NAME, app.getName());
// Read application bindings.
// They are not supposed to exist for new applications, but let's be flexible about it.
ConfigurationUtils.loadApplicationBindings( app );
// Register the application
ManagedApplication ma = new ManagedApplication( app );
this.nameToManagedApplication.put( name, ma );
// Save the instances!
ConfigurationUtils.saveInstances( ma );
this.logger.info( "Application " + name + " was successfully created from the template " + tpl + "." );
return ma;
}
@Override
public void bindApplication( ManagedApplication ma, String externalExportPrefix, String applicationName )
throws UnauthorizedActionException, IOException {
Application app = findApplicationByName( applicationName );
if( app == null )
throw new UnauthorizedActionException( "Application " + applicationName + " does not exist." );
if( ! externalExportPrefix.equals( app.getTemplate().getExternalExportsPrefix()))
throw new UnauthorizedActionException( "Application " + applicationName + "'s template does not have " + externalExportPrefix + " as external exports prefix." );
ma.getApplication().applicationBindings.put( externalExportPrefix, applicationName );
ConfigurationUtils.saveApplicationBindings( ma.getApplication());
this.logger.fine( "External prefix " + externalExportPrefix + " is now bound to application " + applicationName + " in " + ma.getName() + "." );
for( Instance inst : InstanceHelpers.findAllScopedInstances( ma.getApplication())) {
MsgCmdChangeBinding msg = new MsgCmdChangeBinding( app.getTemplate().getExternalExportsPrefix(), applicationName );
this.messagingMngr.sendMessageSafely( ma, inst, msg );
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy