/*
* Copyright (C) 2008 Universidade Federal de Campina Grande
*
* This file is part of OurGrid.
*
* OurGrid is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.ourgrid.common.executor;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import br.edu.ufcg.lsd.commune.container.logging.CommuneLogger;
public class Win32Executor extends VanillaExecutor {
private static final long serialVersionUID = 33L;
/**
* The native process abstract representation. It is used to control the
* execution of command.
*/
private Process process = null;
/** This is the next handle can be issued. */
private int nextHandle = 0;
public Win32Executor(CommuneLogger logger) {
super(logger);
}
public void prepareAllocation() throws ExecutorException {
// TODO Auto-generated method stub
}
/*
* (non-Javadoc)
*
* @see broker.common.Executor#chmod(File file, int mode)
*/
public void chmod( File file, String mode ) throws ExecutorException {
return;
}
/**
* Execute a command like a OS native script. This a method used by the
* Executor class in order to provide some facilities provided by shell. For
* example, wild cards expansion.
*
* @param command The command must be executed
* @param dirName The directory where the execution will be started.
* @return The result (stdout and stderr) of the command execution
* @throws ExecutorException If the execution could not be performed.
*/
public ExecutorHandle execute( String dirName, String command ) throws ExecutorException {
return execute( dirName, command, new LinkedHashMap() );
}
/*
* (non-Javadoc)
*
* @see broker.common.Executor#executeScript(String command, String dirName,
* Map envVars)
*/
public ExecutorHandle execute( String dirName, String command, Map envVars ) throws ExecutorException {
/* The handle for this execution. */
ExecutorHandle handle;
/* Get a new one */
handle = this.getNextHandle();
/* An script created to provide shell facilities for command execution */
File script = createScript( command, dirName, envVars );
getLogger().debug( "About to invoke cmd /C " + script.getPath() + " command: " + command );
try {
/* Invoke the native method of command executino */
process = Runtime.getRuntime().exec( "cmd /C \"" + script.getPath() + "\"" );
/** Register one more */
this.includeInProcesses( handle, process );
/* get the process output */
// result = this.catchOutput(process);
} catch ( IOException e ) {
throw new ExecutorException( command, e );
// } catch (InterruptedException e) {
// throw new ExecutorException(command, e );
}
script.deleteOnExit();
return handle;
}
/**
* Yet to be implemented... (non-Javadoc)
*
* @see org.ourgrid.common.executor.Executor#getResult(org.ourgrid.common.executor.ExecutorHandle)
*/
public ExecutorResult getResult( ExecutorHandle handle ) throws ExecutorException {
ExecutorResult result = null;
Process processToWait = null;
try {
/* Get the reference to the process will return ther result */
processToWait = this.getProcess( handle );
/* get the process output */
result = this.catchOutput( processToWait );
removeFromProcesses( handle );
} catch ( InterruptedException e ) {
throw new ExecutorException( "Cannot get the result of command execution.", e );
}
return result;
}
/*
* (non-Javadoc)
*
* @see broker.common.Executor#createScript(java.lang.String,
* java.lang.String, java.util.Map)
*/
protected File createScript( String command, String dirName, Map envVars ) throws ExecutorException {
/* Create a file object to represent the name of execution root dir */
File dir;
dirName = convert2WinStyle( dirName );
command = convert2WinStyle( command );
getLogger().debug( "Creating script on dir..." + dirName + " for command " + command );
/* The script created by this method to execute the command */
File temporaryScript;
/* A Buffer Writer to produce the temporary script file contents */
BufferedWriter bwTemp = null;
/*
* The keys in the map of environment variables. The name of variables.
*/
Iterator keys;
/* The command used to set environement variables */
String setCommand = "set ";
/* Create the file abstraction to the dirName */
dir = new File( dirName );
getLogger().debug( "Will create file on dir " + dir + " is Directory: " + dir.isDirectory() );
/* Check if the dirName actually refers to a directory */
if ( !dirName.equals( "." ) && !dir.isDirectory() ) {
throw new ExecutorException( command, new FileNotFoundException( dir.getAbsolutePath() ) );
}
getLogger().debug( "Will create file on dir " + dir + " command: " + command );
/* Init the file object represents the command to be executed */
new File( dir, command );
try {
/*
* This is an important phase. The idea is that Win32 platform just
* recognize exe, com, bat and pif like executable files. Therefore,
* this layer need to be aware about it.
*/
temporaryScript = File.createTempFile( "broker", ".bat", dir );
temporaryScript.deleteOnExit();
bwTemp = new BufferedWriter( new FileWriter( temporaryScript ) );
// turns echo off [needed]
bwTemp.write( "@echo off" );
bwTemp.newLine();
if ( envVars != null ) {
/* Get the itarator for the var map */
keys = envVars.keySet().iterator();
if ( keys.hasNext() ) {
while ( keys.hasNext() ) {
String theKey = ( String ) keys.next();
bwTemp.write( setCommand + " " + theKey + "=" + envVars.get( theKey ) + "" );
bwTemp.newLine();
}
bwTemp.newLine();
}
}
bwTemp.write( "cd " + dirName );
bwTemp.newLine();
bwTemp.write( command );
bwTemp.newLine();
bwTemp.flush();
bwTemp.close();
return temporaryScript;
} catch ( IOException ioe ) {
throw new ExecutorException( command, ioe );
} finally {
try {
if ( bwTemp != null ) {
bwTemp.close();
}
} catch ( IOException e ) {
getLogger().debug( "Failed to close stream on Exception." );
}
}
}
/*
* (non-Javadoc)
*
* @see broker.common.Executor#createScript(java.lang.String,
* java.lang.String)
*/
protected File createScript( String command, String dirName ) throws ExecutorException {
return this.createScript( command, dirName, null );
}
/**
* This method is responsible to convert some linux variables and separators
* styles to Windows' ones
*
* @param inn String containing the text that should be processed and if
* necessary converted to windows style
* @return The string converted for windows' format
*/
public static String convert2WinStyle( String inn ) {
StringBuffer sb = new StringBuffer( inn );
Pattern p = Pattern.compile( "\\${1}[1-9a-zA-Z]+" );
Matcher m = p.matcher( inn );
int increased = 0;
while ( m.find() ) {
sb.replace( m.start() + increased, m.start() + increased + 1, "%" );
sb.insert( m.end() + increased, "%" );
increased++;
}
return sb.toString().replace( '/', '\\' );
// TODO Verify if we should also do replace(':',';')
}
/**
* Adds a process into the set of the ones which results were not collected
* yet.
*
* @param handle The handle for the process
* @param process The process to be included at the group
*/
protected synchronized void includeInProcesses( ExecutorHandle handle, Process process ) {
getHandleEntries().put( handle, new HandleEntry(handle, process, "") );
}
/**
* This method manage the handles issued for each command execution
*
* @return A handle to be used by the client to identify its execution
*/
protected synchronized ExecutorHandle getNextHandle( ) {
/** Produce a new handle */
IntegerExecutorHandle newHandle = new IntegerExecutorHandle( nextHandle );
/** Increment the handle pointer */
this.nextHandle++;
return newHandle;
}
public void killPreparingAllocation() throws ExecutorException {
// TODO Auto-generated method stub
}
public void finishCommandExecution(ExecutorHandle handle) throws ExecutorException {
// TODO Auto-generated method stub
}
@Override
public void shutdown() throws ExecutorException {
// TODO Auto-generated method stub
}
}