/**
* Copyright (C) 2013 Colorado School of Mines
*
* This file is part of the Interface Software Development Kit (SDK).
*
* The InterfaceSDK is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The InterfaceSDK 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the InterfaceSDK. If not, see <http://www.gnu.org/licenses/>.
*/
package edu.mines.acmX.exhibit.module_management.modules.implementation;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.rmi.RemoteException;
import java.util.InputMismatchException;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.CountDownLatch;
import edu.mines.acmX.exhibit.input_services.hardware.*;
import edu.mines.acmX.exhibit.input_services.hardware.devicedata.DeviceDataInterface;
import edu.mines.acmX.exhibit.input_services.hardware.drivers.InvalidConfigurationFileException;
import edu.mines.acmX.exhibit.module_management.loaders.ModuleLoader;
import edu.mines.acmX.exhibit.module_management.metas.DependencyType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import edu.mines.acmX.exhibit.module_management.ModuleManager;
import edu.mines.acmX.exhibit.module_management.ModuleManagerRemote;
import edu.mines.acmX.exhibit.module_management.loaders.ManifestLoadException;
import edu.mines.acmX.exhibit.module_management.loaders.ModuleLoadException;
import edu.mines.acmX.exhibit.module_management.metas.ModuleMetaData;
import edu.mines.acmX.exhibit.module_management.modules.ModuleInterface;
/**
* This class is meant to be used as a delegated class instance inside other
* classes implementing ModuleInterface such as ProcessingModule,
* CommandlineModule, etc. Note that this class is part of a multiple
* inheritance design pattern for java. If java ever gets its shit together this
* will most likely all change, but as it is we are pretty confident in javas
* inability to pull its head of a hole in the ground.
*
* <h5>History</h5> Again this class arose from a predicament by the team trying
* to have classes such as ProcessingModule to have a parent of both a PApplet
* and a Module. The solution to this was to wrap up the desired functionality
* into a ModuleInterface. Each abstract Module class such as Processing Module
* would implement this interface (multiple implementing is allowed in java).
* Because the implementation for the ModuleInterface would be the same between
* all the implementing Modules we added a concrete ModuleHelper class to
* contain these implementation details. This allows abstract Modules (i.e.
* ProcessingModule) to implement ModuleInterface by delegating these methods to
* the ModuleHelper.
*
* @author Andrew DeMaria
* @author Austin Diviness
*/
public class ModuleHelper implements ModuleInterface {
private static Logger log = LogManager.getLogger(ModuleHelper.class);
private static boolean hardwareFirstRun = true;
public ModuleHelper() {
// no op
}
protected ModuleManagerRemote getManager()
throws ModuleManagerCommunicationException {
try {
return ModuleManager.getInstance();
} catch (ManifestLoadException e) {
String msg = "Could not get instance of ModuleManager in ModuleHelper";
log.fatal(msg);
throw new ModuleManagerCommunicationException();
} catch (ModuleLoadException e) {
String msg = "Could not get instance of ModuleManager in ModuleHelper";
log.fatal(msg);
throw new ModuleManagerCommunicationException();
}
}
protected synchronized HardwareManagerRemote getHardware() throws HardwareManagerCommunicationException,
ModuleManagerCommunicationException, BadDeviceFunctionalityRequestException,
InvalidConfigurationFileException, BadFunctionalityRequestException {
try {
HardwareManager hm = HardwareManager.getInstance();
if( hardwareFirstRun ) {
Map<String,DependencyType> requestedInputs;
try {
hm.setConfigurationFileStore(getConfigurations());
ModuleMetaData self = getModuleMetaData(getCurrentModulePackageName());
requestedInputs = self.getInputTypes();
} catch (RemoteException e) {
throw new ModuleManagerCommunicationException();
}
hm.checkPermissions(requestedInputs);
hm.setRunningModulePermissions(requestedInputs);
hm.resetAllDrivers();
hardwareFirstRun = false;
}
return hm;
} catch (HardwareManagerManifestException e) {
throw new HardwareManagerCommunicationException();
}
}
// just a slim layer for interfacing with a modulemanager and will return a
// boolean on whether the requested module can be run.
/**
* Sets the next module to be loaded by the Module Manager
*
* @param moduleName
* The package name of the next module to be loaded
*
* @return true if successful, false otherwise
*/
@Override
public boolean setNextModule(String moduleName) {
try {
return getManager().setNextModule(moduleName);
} catch (RemoteException e) {
// TODO throw instead of catch
return false;
}
}
@Override
public InputStream loadResourceFromModule(String jarResourcePath,
ModuleMetaData m) throws ManifestLoadException,
ModuleLoadException, RemoteException {
log.debug("We will now load resource from the ModuleLoader" );
try {
return ModuleLoader.loadResource( getManager().getPathToModules() + "/"
+ m.getJarFileName(), m, this.getClass()
.getClassLoader(), jarResourcePath );
} catch (MalformedURLException e) {
log.warn("Could not load the given resource do to a malormed path");
return null;
} catch (ModuleLoadException e) {
log.warn("Could not load the given resource because the Modules jar could not be loaded");
return null;
}
}
@Override
public InputStream loadResourceFromModule(String jarResourcePath)
throws ManifestLoadException, ModuleLoadException, RemoteException {
return loadResourceFromModule( jarResourcePath, getManager().getCurrentModulePackageName());
}
@Override
public InputStream loadResourceFromModule( String jarResourcePath, String packageName )
throws RemoteException, ManifestLoadException, ModuleLoadException {
return loadResourceFromModule( jarResourcePath, getManager().getModuleMetaData( packageName ) );
}
@Override
public ModuleMetaData getModuleMetaData(String packageName) throws ModuleManagerCommunicationException, RemoteException {
return getManager().getModuleMetaData( packageName );
}
@Override
public String[] getAllAvailableModules() throws RemoteException {
return getManager().getAllAvailableModules();
}
@Override
public String getCurrentModulePackageName() throws RemoteException {
return getManager().getCurrentModulePackageName();
}
@Override
public void execute() {
// Never used
}
@Override
public ModuleMetaData getDefaultModuleMetaData() throws RemoteException {
return getManager().getDefaultModuleMetaData();
}
@Override
public String next() throws RemoteException {
return getManager().next();
}
@Override
public int nextInt() throws RemoteException {
return getManager().nextInt();
}
@Override
public Map<String, String> getConfigurations() throws RemoteException {
return getManager().getConfigurations();
}
@Override
public String getPathToModules() throws RemoteException {
return getManager().getPathToModules();
}
@Override
public DeviceDataInterface getInitialDriver(String functionality) throws RemoteException,
BadFunctionalityRequestException, UnknownDriverRequest, InvalidConfigurationFileException,
BadDeviceFunctionalityRequestException {
try {
return getHardware().getInitialDriver(functionality);
} catch (Exception e) { //If we have any problem getting the driver, try again
System.out.println("Retrying getting the driver in ModuleHelper");
((HardwareManager)getHardware()).resetAllDrivers();
return getHardware().getInitialDriver(functionality);
} //TODO preferably something other than this method
}
}