package org.openbel.framework.tools;
import static java.lang.String.*;
import static org.openbel.framework.common.BELUtilities.*;
import static org.openbel.framework.common.Strings.*;
import static org.openbel.framework.common.cfg.SystemConfiguration.*;
import static org.openbel.framework.tools.PhaseFourOptions.*;
import java.io.File;
import java.util.Date;
import java.util.List;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.openbel.framework.api.internal.KamDbObject;
import org.openbel.framework.common.DBConnectionFailure;
import org.openbel.framework.common.cfg.SystemConfiguration;
import org.openbel.framework.common.enums.ExitCode;
import org.openbel.framework.common.protonetwork.model.ProtoNetwork;
import org.openbel.framework.common.protonetwork.model.ProtoNetworkError;
import org.openbel.framework.common.util.BELPathFilters.GlobalProtonetworkFilter;
import org.openbel.framework.compiler.DefaultPhaseFour;
import org.openbel.framework.compiler.PhaseFourImpl;
import org.openbel.framework.compiler.kam.KAMStoreSchemaService;
import org.openbel.framework.compiler.kam.KAMStoreSchemaServiceImpl;
import org.openbel.framework.core.compiler.CreateKAMFailure;
import org.openbel.framework.core.df.DBConnection;
import org.openbel.framework.core.df.DatabaseError;
import org.openbel.framework.core.df.DatabaseService;
import org.openbel.framework.core.df.DatabaseServiceImpl;
import org.openbel.framework.core.kam.KAMCatalogFailure;
import org.openbel.framework.core.protonetwork.BinaryProtoNetworkDescriptor;
import org.openbel.framework.core.protonetwork.BinaryProtoNetworkExternalizer;
import org.openbel.framework.core.protonetwork.ProtoNetworkDescriptor;
/**
* BEL phase four compiler.
*
* @author Anthony Bargnesi {@code <abargnesi@selventa.com>}
*/
public final class PhaseFourApplication extends PhaseApplication {
private final static String SHORT_OPT_KAM_DESCRIPTION = "d";
private final static String LONG_OPT_KAM_DESCRIPTION = "kam-description";
private final DefaultPhaseFour p4;
private final SystemConfiguration sysconfig;
private final static String numPhases = "1";
/**
* Holds the value of the KAM name option.
*/
private String kamName;
/**
* Holds the value of the KAM description option.
*/
private String kamDescription;
/**
* Phase four application constructor.
*
* @param args Command-line arguments
*/
public PhaseFourApplication(String[] args) {
super(args);
sysconfig = getSystemConfiguration();
DatabaseService dbservice = new DatabaseServiceImpl();
KAMStoreSchemaService kamStoreSchemaService = new KAMStoreSchemaServiceImpl(
dbservice);
p4 = new PhaseFourImpl(dbservice, kamStoreSchemaService);
}
/**
* {@inheritDoc}
*/
@Override
public void start() {
super.start();
// Fail if no KAM name is available
kamName = getOptionValue(SHORT_OPT_KAM_NAME);
if (kamName == null) {
kamName = getPhaseConfiguration().getKAMName();
if (kamName == null) {
error(MISSING_KAM_NAME);
failUsage();
}
}
// Fail if no KAM description is available
kamDescription = getOptionValue(SHORT_OPT_KAM_DESCRIPTION);
if (kamDescription == null) {
kamDescription = getPhaseConfiguration().getKAMDescription();
if (kamDescription == null) {
error(MISSING_KAM_DESCRIPTION);
failUsage();
}
}
processOutputDirectory();
}
/**
* Process output directory.
*/
private void processOutputDirectory() {
// Phase IV may have to use the proto network output of phase II if
// phase III is skipped.
final String outputPath = outputDirectory.getAbsolutePath();
final String[] args = getCommandLineArguments();
final PhaseThreeApplication p3App = new PhaseThreeApplication(args);
String folder;
// if phase III was skipped or no orthology documents were merged
if (p3App.isSkipped()) {
folder = PhaseTwoApplication.DIR_ARTIFACT;
} else {
folder = PhaseThreeApplication.DIR_ARTIFACT;
}
final File pnPath = new File(asPath(outputPath, folder));
// Fail if path is not a directory
if (!pnPath.isDirectory()) {
error(NOT_A_DIRECTORY + ": " + pnPath);
failUsage();
}
final File[] files = pnPath.listFiles(new GlobalProtonetworkFilter());
if (files.length == 0 || files.length > 1) {
bail(ExitCode.NO_GLOBAL_PROTO_NETWORK);
}
processFiles(files[0]);
}
/**
* Starts phase four creation of KAM.
*
* @param protoNetwork {@link File}, the proto network file
*/
private void processFiles(File protoNetwork) {
// final StringBuilder bldr = new StringBuilder();
// bldr.append("Executing ");
// bldr.append(getApplicationName());
// bldr.append(" of ");
// bldr.append(protoNetwork);
// phaseOutput(bldr.toString());
phaseOutput(format("=== %s ===", getApplicationName()));
ProtoNetworkDescriptor pnd = new BinaryProtoNetworkDescriptor(
protoNetwork);
BinaryProtoNetworkExternalizer bpne =
new BinaryProtoNetworkExternalizer();
ProtoNetwork gpn = null;
try {
gpn = bpne.readProtoNetwork(pnd);
} catch (ProtoNetworkError e) {
error("Unable to read merged network.");
exit(ExitCode.NO_GLOBAL_PROTO_NETWORK);
}
stage1(gpn);
}
/**
* Stage one connection to KAM store.
*
* @return {@link DBConnection}, the KAM DB connection
*/
private void stage1(ProtoNetwork gpn) {
beginStage(PHASE4_STAGE1_HDR, "1", numPhases);
final StringBuilder bldr = new StringBuilder();
final String kamURL = sysconfig.getKamURL();
final String kamUser = sysconfig.getKamUser();
final String kamPass = sysconfig.getKamPassword();
// stageOutput("Building KAM at - " + kamURL);
DBConnection dbc = null;
try {
dbc = p4.stage1ConnectKAMStore(kamURL, kamUser, kamPass);
} catch (DBConnectionFailure e) {
e.printStackTrace();
stageError(e.getUserFacingMessage());
exit(ExitCode.KAM_CONNECTION_FAILURE);
}
KamDbObject kamDb = new KamDbObject(null, kamName, kamDescription,
new Date(), null);
String kamSchemaName = null;
try {
kamSchemaName = p4.stage2SaveToKAMCatalog(kamDb);
} catch (KAMCatalogFailure e) {
e.printStackTrace();
stageError(e.getUserFacingMessage());
exit(ExitCode.KAM_CONNECTION_FAILURE);
}
try {
p4.stage3CreateKAMstore(dbc, kamSchemaName);
} catch (CreateKAMFailure e) {
e.printStackTrace();
stageError("Unable to build KAM store - " + e.getMessage());
exit(ExitCode.KAM_CONNECTION_FAILURE);
}
try {
p4.stage4LoadKAM(dbc, gpn, kamSchemaName);
} catch (DatabaseError e) {
stageError("Unable to load KAM.");
stageError(e.getUserFacingMessage());
exit(ExitCode.KAM_LOAD_FAILURE);
} catch (CreateKAMFailure e) {
stageError("Unable to build KAM store - " + e.getMessage());
exit(ExitCode.KAM_CONNECTION_FAILURE);
}
markEndStage(bldr);
}
/**
* {@inheritDoc}
*/
@Override
public PhaseFourOptions getPhaseConfiguration() {
return phaseFourOptions();
}
/**
* {@inheritDoc}
*/
@Override
public boolean validCommandLine() {
final CommandLineParser parser = new AntelopeParser();
List<Option> myOpts = getCommandLineOptions();
final Options options = new Options();
for (final Option option : myOpts) {
options.addOption(option);
}
CommandLine parse;
try {
parse = parser.parse(options, getCommandLineArguments(), false);
} catch (ParseException e) {
return false;
}
// Verify KAM name and description are present.
if (!parse.hasOption(SHORT_OPT_KAM_NAME)) {
if (getPhaseConfiguration().getKAMName() == null) {
return false;
}
}
if (!parse.hasOption(SHORT_OPT_KAM_DESCRIPTION)) {
if (getPhaseConfiguration().getKAMDescription() == null) {
return false;
}
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public List<Option> getCommandLineOptions() {
List<Option> options = super.getCommandLineOptions();
String help;
Option o;
help = KAM_DESCRIPTION_HELP;
o = new Option(SHORT_OPT_KAM_DESCRIPTION, LONG_OPT_KAM_DESCRIPTION,
true, help);
o.setArgName("description");
options.add(o);
help = KAM_NAME_HELP;
o = new Option(SHORT_OPT_KAM_NAME, LONG_OPT_KAM_NAME, true, help);
o.setArgName("kam");
options.add(o);
return options;
}
/**
* Returns {@code "Phase V: Exporting final network to the KAM store"}.
*
* @return String
*/
@Override
public String getApplicationName() {
return PHASE4_NAME;
}
/**
* Returns {@code "Phase V"}.
*
* @return String
*/
@Override
public String getApplicationShortName() {
return PHASE4_SHORT_NAME;
}
/**
* Returns {@code "Compiles the global proto-network into a KAM."}.
*
* @return String
*/
@Override
public String getApplicationDescription() {
return PHASE4_DESCRIPTION;
}
/**
* Returns phase four's usage.
*
* @return String
*/
@Override
public String getUsage() {
StringBuilder bldr = new StringBuilder();
bldr.append("[OPTION]...");
bldr.append(" -k <kam>");
bldr.append(" -d <description>");
return bldr.toString();
}
/**
* Invokes {@link #harness(PhaseApplication)} for
* {@link PhaseFourApplication}.
*
* @param args Command-line arguments
*/
public static void main(String[] args) {
harness(new PhaseFourApplication(args));
}
/**
* {@inheritDoc}
*/
public static String getRequiredArguments() {
return "-k <kam> --kam-description <description>";
}
}