/******************************************************************************
* Copyright (c) 2007 g-Eclipse consortium
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Initial development of the original code was made for
* project g-Eclipse founded by European Union
* project number: FP6-IST-034327 http://www.geclipse.eu/
*
* Contributor(s):
* PSNC - Katarzyna Bylec
*
*****************************************************************************/
package eu.geclipse.jsdl.ui.preference;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.compare.IContentChangeListener;
import org.eclipse.compare.IContentChangeNotifier;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import eu.geclipse.core.ICoreProblems;
import eu.geclipse.core.model.GridModel;
import eu.geclipse.core.model.IGridApplication;
import eu.geclipse.core.model.IGridApplicationParameters;
import eu.geclipse.core.model.IGridElement;
import eu.geclipse.core.model.IGridResource;
import eu.geclipse.core.model.IVirtualOrganization;
import eu.geclipse.core.model.impl.GridApplicationParameters;
import eu.geclipse.core.model.impl.GridResourceCategoryFactory;
import eu.geclipse.core.reporting.ProblemException;
import eu.geclipse.jsdl.ui.internal.Activator;
/**
* Register that manages {@link GridApplicationParameters}, which are created,
* removed and edited while gEclipse is run. Those objects are serialized, so
* there are accessible after Eclipse is restarted. This class is singleton.
*/
public class ApplicationParametersRegistry implements IContentChangeNotifier {
private static final String DIRECTORY_NAME = ".appsData"; //$NON-NLS-1$
private static final String APP_NAME_PREFIX = "appName="; //$NON-NLS-1$
private static final String APP_PATH_PREFIX = "appPath="; //$NON-NLS-1$
private static final String XML_PATH_PREFIX = "XMLPath="; //$NON-NLS-1$
private static final String JSDL_PATH_PEFIX = "JSDLPath="; //$NON-NLS-1$
private static final String VO_PATH_PREFIX = "VOName="; //$NON-NLS-1$
private static ApplicationParametersRegistry instance;
int currentIdPointer = 0;
private List<IGridApplicationParameters> userAppsParamsList = new ArrayList<IGridApplicationParameters>()
{
/**
*
*/
private static final long serialVersionUID = -6190123705427391030L;
@Override
public boolean add( final IGridApplicationParameters param ) {
param.setId( ApplicationParametersRegistry.this.currentIdPointer );
ApplicationParametersRegistry.this.currentIdPointer++;
return super.add( param );
}
};
private List<IGridApplicationParameters> generatedAppsParamList = new ArrayList<IGridApplicationParameters>()
{
/**
*
*/
private static final long serialVersionUID = 1433643044865859460L;
@Override
public boolean add( final IGridApplicationParameters param ) {
param.setId( ApplicationParametersRegistry.this.currentIdPointer );
ApplicationParametersRegistry.this.currentIdPointer++;
return super.add( param );
}
};
private Map<IGridApplicationParameters, String> appSpecObjectsToFiles = new HashMap<IGridApplicationParameters, String>();
private ListenerList ccListeners = new ListenerList();
private ApplicationParametersRegistry() {
this.userAppsParamsList = new ArrayList<IGridApplicationParameters>();
IPath location = Activator.getDefault().getStateLocation();
location = location.append( ApplicationParametersRegistry.DIRECTORY_NAME );
File file = location.toFile();
if( file.exists() ) {
String[] names = file.list();
for( String name : names ) {
GridApplicationParameters asO = readDataFile( ( new Path( file.getAbsolutePath() ) ).append( name ) );
if( asO != null ) {
this.userAppsParamsList.add( asO );
}
}
}
}
/**
* Returns the only instance (singleton) of this registry. If this instance
* was not created yet - this method will trigger a constructor.
*
* @return singleton instance of registry
*/
public static ApplicationParametersRegistry getInstance() {
if( instance == null ) {
instance = new ApplicationParametersRegistry();
}
return instance;
}
/**
* Returns stored values of applications' parameters for given virtual
* organization.
*
* @param vo virtual organization for which applications' parameters will be
* returned. This value can be <code>null</code> - indicating
* that parameters for all available virtual organizations should
* be returned.
* @return list of applications' parameters stored by this registry. To make
* sure you will get the most up-to-date values call
* {@link ApplicationParametersRegistry#updateApplicationsParameters(IVirtualOrganization, IProgressMonitor)}
* before calling this method.
*/
public List<IGridApplicationParameters> getApplicationParameters( final IVirtualOrganization vo )
{
List<IGridApplicationParameters> result = new ArrayList<IGridApplicationParameters>();
for( IGridApplicationParameters param : this.userAppsParamsList ) {
if( vo == null || param.getVO().equals( vo ) ) {
result.add( param );
}
}
for( IGridApplicationParameters param : this.generatedAppsParamList ) {
if( vo == null || param.getVO().equals( vo ) ) {
result.add( param );
}
}
return result;
}
/**
* Updates registry with most up-to-date values of applications' parameters of
* a given virtual organization. Calling this method results in contacting
* info service and replacing data held by this data with new values obtained
* from this service. </br>This method do not affects applications parameters
* defined by user through user interface .
*
* @param vo virtual organization for which applications' parameters will be
* updated. This value can be <code>null</code> - indicating that
* parameters for all available virtual organizations should be
* updated.
* @param monitor this may be a long-running operation. Parent method calling
* this operation should provide a progress monitor for it.
* @throws ProblemException it is thrown in case registry was not able to
* access resources
*/
public void updateApplicationsParameters( final IVirtualOrganization vo,
final IProgressMonitor monitor )
throws ProblemException
{
monitor.beginTask( Messages.getString( "ApplicationParametersRegistry.fetching_information" ), IProgressMonitor.UNKNOWN ); //$NON-NLS-1$
if( vo == null ) {
IGridElement[] els;
els = GridModel.getVoManager().getChildren( new NullProgressMonitor() );
monitor.worked( 1 );
for( IGridElement el : els ) {
if( el instanceof IVirtualOrganization ) {
IVirtualOrganization singleVO = ( IVirtualOrganization )el;
List<IGridApplicationParameters> params = new ArrayList<IGridApplicationParameters>();
IGridResource[] resources = null;
monitor.setTaskName( Messages.getString( "ApplicationParametersRegistry.fetching_apps_list" ) ); //$NON-NLS-1$
resources = singleVO.getAvailableResources( GridResourceCategoryFactory.getCategory( GridResourceCategoryFactory.ID_APPLICATIONS ),
false,
new NullProgressMonitor() );
monitor.worked( 1 );
if( resources != null ) {
for( IGridResource param : resources ) {
monitor.setTaskName( Messages.getString( "ApplicationParametersRegistry.processing_apps_data" ) ); //$NON-NLS-1$
IGridApplicationParameters parameter = ( ( IGridApplication )param ).getApplicationParameters();
if( parameter != null ) {
params.add( parameter );
}
monitor.worked( 1 );
}
} else {
throw new ProblemException( ICoreProblems.MODEL_FETCH_CHILDREN_FAILED,
Messages.getString( "ApplicationParametersRegistry.cannot_fetch_resources" ), //$NON-NLS-1$
Activator.PLUGIN_ID );
}
monitor.setTaskName( Messages.getString( "ApplicationParametersRegistry.updating_registry" ) ); //$NON-NLS-1$
replaceParametersForVO( singleVO, params );
monitor.worked( 1 );
}
}
} else {
monitor.beginTask( Messages.getString( "ApplicationParametersRegistry.fetching_apps_list" ), //$NON-NLS-1$
IProgressMonitor.UNKNOWN );
List<IGridApplicationParameters> params = new ArrayList<IGridApplicationParameters>();
IGridResource[] resources = null;
resources = vo.getAvailableResources( GridResourceCategoryFactory.getCategory( GridResourceCategoryFactory.ID_APPLICATIONS ),
false,
new NullProgressMonitor() );
if( resources != null ) {
for( IGridResource param : resources ) {
monitor.setTaskName( Messages.getString( "ApplicationParametersRegistry.processing_apps_data" ) ); //$NON-NLS-1$
IGridApplicationParameters parameter = ( ( IGridApplication )param ).getApplicationParameters();
if( parameter != null ) {
params.add( parameter );
}
monitor.worked( 1 );
}
} else {
throw new ProblemException( ICoreProblems.MODEL_FETCH_CHILDREN_FAILED,
Messages.getString( "ApplicationParametersRegistry.cannot_fetch_resources" ), //$NON-NLS-1$
Activator.PLUGIN_ID );
}
monitor.setTaskName( Messages.getString( "ApplicationParametersRegistry.updating_registry" ) ); //$NON-NLS-1$
replaceParametersForVO( vo, params );
monitor.worked( 1 );
}
}
/**
* Done for {@link ApplicationParametersRegistry#generatedAppsParamList} list.
*
* @param vo
* @param newParams
*/
private void replaceParametersForVO( final IVirtualOrganization vo,
final List<IGridApplicationParameters> newParams )
{
removeParamsForVO( vo );
internalAddParams( newParams, 1 );
}
private void internalAddParams( final List<IGridApplicationParameters> newParams,
final int list )
{
if( list == 1 ) {
for( IGridApplicationParameters param : newParams ) {
this.generatedAppsParamList.add( param );
notifyListeners();
}
} else if( list == 0 ) {
for( IGridApplicationParameters param : newParams ) {
try {
saveObjectToDisc( param );
this.userAppsParamsList.add( param );
notifyListeners();
} catch( IOException e ) {
// ignore
}
}
}
}
private void removeParamsForVO( final IVirtualOrganization vo ) {
Iterator<IGridApplicationParameters> iterator = this.generatedAppsParamList.iterator();
while( iterator.hasNext() ) {
IGridApplicationParameters param = iterator.next();
if( param.getVO().equals( vo ) ) {
iterator.remove();
notifyListeners();
}
}
}
private boolean removeParam( final IGridApplicationParameters param ) {
boolean result = false;
String fileName = this.appSpecObjectsToFiles.get( param );
IPath path = Activator.getDefault().getStateLocation();
path = path.append( ApplicationParametersRegistry.DIRECTORY_NAME );
path = path.append( this.appSpecObjectsToFiles.get( param ) );
if( fileName != null ) {
File file = path.toFile();
file.exists();
result = file.delete();
} else {
result = true;
}
if( result ) {
if( this.userAppsParamsList.contains( param ) ) {
this.userAppsParamsList.remove( param );
} else if( this.generatedAppsParamList.contains( param ) ) {
this.generatedAppsParamList.remove( param );
}
}
return result;
}
private void saveObjectToDisc( final IGridApplicationParameters aSO )
throws IOException
{
IPath path = Activator.getDefault().getStateLocation();
path = path.append( ApplicationParametersRegistry.DIRECTORY_NAME );
File directory = path.toFile();
if( !directory.exists() ) {
directory.mkdir();
}
int name = aSO.getId();
boolean canCreate = false;
while( !canCreate ) {
if( path.append( Integer.valueOf( name ).toString() ).toFile().exists() )
{
name++;
} else {
path = path.append( Integer.valueOf( name ).toString() );
canCreate = true;
}
}
File newFile = path.toFile();
newFile.createNewFile();
FileWriter writer = new FileWriter( newFile, true );
writer.write( ApplicationParametersRegistry.APP_NAME_PREFIX
+ aSO.getApplicationName()
+ "\n" ); //$NON-NLS-1$
writer.write( ApplicationParametersRegistry.APP_PATH_PREFIX
+ aSO.getApplicationPath()
+ "\n" ); //$NON-NLS-1$
writer.write( ApplicationParametersRegistry.XML_PATH_PREFIX
+ aSO.getXmlPath()
+ "\n" ); //$NON-NLS-1$
writer.write( ApplicationParametersRegistry.JSDL_PATH_PEFIX
+ aSO.getJsdlPath()
+ "\n" ); //$NON-NLS-1$
String vo = ""; //$NON-NLS-1$
if( aSO.getVO() != null ) {
vo = aSO.getVO().getName();
}
writer.write( ApplicationParametersRegistry.VO_PATH_PREFIX + vo );
writer.close();
this.appSpecObjectsToFiles.put( aSO, Integer.valueOf( name ).toString() );
}
/**
* Method to read application specific data form file at given location.
* Method is silent when something is wrong with the file - it only logs an
* exception
*
* @param filePath path to file with application specific data
* @return an instance of {@link GridApplicationParameters} or null if
* something goes wrong (e.g. file is not found or has malformed data)
*/
private GridApplicationParameters readDataFile( final IPath filePath ) {
GridApplicationParameters result = null;
File file = filePath.toFile();
if( file.isFile() ) {
BufferedReader in = null;
try {
in = new BufferedReader( new FileReader( file ) );
String line;
String appName = null;
String path = null;
IPath xmlPath = null;
IPath jsdlPath = null;
IVirtualOrganization vo = null;
boolean doCreate = true;
while( ( line = in.readLine() ) != null ) {
if( line.startsWith( ApplicationParametersRegistry.APP_NAME_PREFIX ) )
{
appName = line.substring( ApplicationParametersRegistry.APP_NAME_PREFIX.length() )
.trim();
}
if( line.startsWith( ApplicationParametersRegistry.APP_PATH_PREFIX ) )
{
path = line.substring( ApplicationParametersRegistry.APP_PATH_PREFIX.length() )
.trim();
}
if( line.startsWith( ApplicationParametersRegistry.XML_PATH_PREFIX ) )
{
xmlPath = new Path( line.substring( ApplicationParametersRegistry.XML_PATH_PREFIX.length() )
.trim() );
}
if( line.startsWith( ApplicationParametersRegistry.JSDL_PATH_PEFIX ) )
{
jsdlPath = new Path( line.substring( ApplicationParametersRegistry.JSDL_PATH_PEFIX.length() )
.trim() );
}
if( line.startsWith( ApplicationParametersRegistry.VO_PATH_PREFIX ) )
{
String voName = line.substring( ApplicationParametersRegistry.VO_PATH_PREFIX.length() )
.trim();
if( voName != "" ) { //$NON-NLS-1$
vo = ( IVirtualOrganization )GridModel.getVoManager()
.findChild( voName );
if( vo == null ) {
// this means ASP was defined for VO that cannot be found in
// GridModel
}
} else {
// this means ASP is defined for all VOs
vo = null;
}
}
}
if( appName != null && path != null && xmlPath != null && doCreate ) {
result = new GridApplicationParameters( appName,
path,
xmlPath,
jsdlPath,
vo );
this.appSpecObjectsToFiles.put( result, filePath.lastSegment() );
}
} catch( FileNotFoundException fileNotFoundExc ) {
Activator.logException( fileNotFoundExc );
} catch( IOException ioExc ) {
Activator.logException( ioExc );
} finally {
try {
if( in != null ) {
in.close();
}
} catch( IOException e ) {
// TODO Auto-generated catch block
Activator.logException( e );
}
}
}
return result;
}
public void addContentChangeListener( final IContentChangeListener listener )
{
if( this.ccListeners == null ) {
this.ccListeners = new ListenerList();
}
this.ccListeners.add( listener );
}
public void removeContentChangeListener( final IContentChangeListener listener )
{
if( this.ccListeners != null ) {
this.ccListeners.remove( listener );
}
}
protected void notifyListeners() {
Object[] list = this.ccListeners.getListeners();
for( int i = 0; i < list.length; i++ ) {
if( list[ i ] instanceof IContentChangeListener ) {
IContentChangeListener listener = ( IContentChangeListener )list[ i ];
listener.contentChanged( this );
}
}
}
/**
* Method for removing application's parameters from registry. All listeners
* are informed that parameter was removed.</br>Note that this can be done
* only for user-defined parameters - not for those fetched from info system,
* as they are defined on "server side" and removing them from registy might
* result in confusion if they are deleted also on "the server side" or not.
*
* @param param parameter to be removed
* @throws ApplicationParametersException is thrown when registry doesn't
* contain user-defined parameter equal to one passed to this
* method
*/
public void removeApplicationParameters( final GridApplicationParameters param )
throws ApplicationParametersException
{
if( this.userAppsParamsList.contains( param ) ) {
if( removeParam( param ) ) {
notifyListeners();
} else {
// TODO katis: Problem Dialog
}
} else {
throw new ApplicationParametersException( new Status( IStatus.ERROR,
Activator.PLUGIN_ID,
Messages.getString( "ApplicationParametersRegistry.removing_not_allowed_exception" ) ) ); //$NON-NLS-1$
}
}
/**
* Method for adding user-defined parameters to this registry. All listeners
* are informed that new parameter was added.
*
* @param appName application name
* @param appPath application executable path, this is optional and may be
* <code>null</code>
* @param xmlPath path to file containing XML definition of JSDL wizard
* additional pages.
* @param jsdlPath path to file containing base JSDL file which will be used
* as a "parent" for JSDL files created for this application.
* @param vo virtual application for which this application is defined,
* <code>null</code> indicates that it is defined for all virtual
* organization available
*/
public void addApplicationSpecificData( final String appName,
final String appPath,
final Path xmlPath,
final Path jsdlPath,
final IVirtualOrganization vo )
{
GridApplicationParameters newObject = new GridApplicationParameters( appName,
appPath,
xmlPath,
jsdlPath,
vo );
if( !this.userAppsParamsList.contains( newObject ) ) {
try {
saveObjectToDisc( newObject );
this.userAppsParamsList.add( newObject );
notifyListeners();
} catch( IOException exc ) {
// TODO katis: problem dialog
Activator.logException( exc );
}
}
}
/**
* Changes given {@link GridApplicationParameters}. In this object given
* values will be set. All listeners are notified of this change. </br>Note
* that this can be done only for user-defined parameters - not for those
* fetched from info system, as they are defined on "server side" and
* modifying them from registy might result in confusion if they are changed
* also on "the server side" or not.
*
* @param oldASO object to change
* @param newAppName application name to change in given
* ApplicationSpecificObject
* @param newAppPath path to executable file to change in given
* ApplicationSpecificObject
* @param newXMLPath path to XML file to change in given
* ApplicationSpecificObject
* @param newJSDLPath path to JSDL file to change in given
* ApplicationSpecificObject
* @throws ApplicationParametersException is thrown when registry doesn't
* contain user-defined parameter equal to one passed to this
* method
*/
public void editApplicationSpecificData( final GridApplicationParameters oldASO,
final String newAppName,
final String newAppPath,
final String newXMLPath,
final String newJSDLPath )
throws ApplicationParametersException
{
IPath path = Activator.getDefault().getStateLocation();
try {
if( this.userAppsParamsList.contains( oldASO ) ) {
path = path.append( ApplicationParametersRegistry.DIRECTORY_NAME );
path = path.append( this.appSpecObjectsToFiles.get( oldASO ) );
FileWriter writer;
writer = new FileWriter( path.toFile(), false );
writer.write( ApplicationParametersRegistry.APP_NAME_PREFIX
+ newAppName
+ "\n" ); //$NON-NLS-1$
writer.write( ApplicationParametersRegistry.APP_PATH_PREFIX
+ newAppPath
+ "\n" ); //$NON-NLS-1$
writer.write( ApplicationParametersRegistry.XML_PATH_PREFIX
+ newXMLPath
+ "\n" ); //$NON-NLS-1$
writer.write( ApplicationParametersRegistry.JSDL_PATH_PEFIX
+ newJSDLPath );
writer.close();
oldASO.setApplicationName( newAppName );
oldASO.setAppPath( newAppPath );
oldASO.setXmlPath( new Path( newXMLPath ) );
oldASO.setJSDLPath( new Path( newJSDLPath ) );
notifyListeners();
} else {
throw new ApplicationParametersException( new Status( IStatus.ERROR,
Activator.PLUGIN_ID,
Messages.getString( "ApplicationParametersRegistry.editing_not_allowed_exception" ) ) ); //$NON-NLS-1$
}
} catch( IOException exc ) {
// TODO katis: problem dialog
Activator.logException( exc );
}
}
/**
* Returns map of applications names as a keys and corresponding application's
* parameters object's id as a value. The key - application name - is modified
* this way that if there are more then one applications with the same name an
* ordinal numeral is added to name. This change affects only list returned by
* this method - not applications' parameters contained by this registry.
*
* @param vo virtual organization for which list of application's parameters
* should be created. <code>null</code> value indicates all
* virtual organizations available.
* @return map of applications names (modified with an ordinal number when
* needed) as a keys and corresponding application's parameters
* object's id as a value
*/
public Map<String, Integer> getApplicationDataMapping( final IVirtualOrganization vo )
{
Map<String, Integer> result = new HashMap<String, Integer>();
List<IGridApplicationParameters> chosenParams = new ArrayList<IGridApplicationParameters>();
Map<String, Integer> nameVsQuantity = new HashMap<String, Integer>();
List<IVirtualOrganization> vos = new ArrayList<IVirtualOrganization>();
if( vo == null ) {
IGridElement[] els = new IGridElement[ 0 ];
try {
els = GridModel.getVoManager().getChildren( new NullProgressMonitor() );
} catch( ProblemException e ) {
// TODO Auto-generated catch block
Activator.logException( e );
}
for( IGridElement el : els ) {
if( el instanceof IVirtualOrganization ) {
vos.add( ( IVirtualOrganization )el );
}
}
} else {
vos.add( vo );
}
for( IGridApplicationParameters param : this.userAppsParamsList ) {
if( vos.contains( param.getVO() ) || param.getVO() == null ) {
chosenParams.add( param );
String appName = param.getApplicationName();
Integer occur = new Integer( 0 );
if( nameVsQuantity.keySet().contains( appName ) ) {
occur = nameVsQuantity.get( appName );
}
nameVsQuantity.put( appName, new Integer( occur.intValue() + 1 ) );
}
}
for( IGridApplicationParameters param : this.generatedAppsParamList ) {
if( vos.contains( param.getVO() ) || param.getVO() == null ) {
chosenParams.add( param );
String appName = param.getApplicationName();
Integer occur = new Integer( 0 );
if( nameVsQuantity.keySet().contains( appName ) ) {
occur = nameVsQuantity.get( appName );
}
nameVsQuantity.put( appName, new Integer( occur.intValue() + 1 ) );
}
}
for( IGridApplicationParameters param : chosenParams ) {
String sufix = ""; //$NON-NLS-1$
for( int i = 1; i <= nameVsQuantity.get( param.getApplicationName() )
.intValue(); i++ )
{
if( i != 1 ) {
sufix = "[" + i + "]"; //$NON-NLS-1$ //$NON-NLS-2$
}
result.put( param.getApplicationName() + sufix,
new Integer( param.getId() ) );
}
}
return result;
}
/**
* Returns application parameter object with given id.
*
* @param paramId id of application parameter object
* @return application parameter object with given id or <code>null</code>
* if registry does not hold object with such id
*/
public IGridApplicationParameters getApplicationData( final int paramId ) {
IGridApplicationParameters result = null;
boolean haveIt = false;
for( IGridApplicationParameters param : this.userAppsParamsList ) {
if( param.getId() == paramId ) {
result = param;
haveIt = true;
break;
}
}
if( !haveIt ) {
for( IGridApplicationParameters param : this.generatedAppsParamList ) {
if( param.getId() == paramId ) {
result = param;
haveIt = true;
break;
}
}
}
return result;
}
}