package tool.repository;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;
import tool.ToolPlugin;
import tool.ToolProjectSupport;
public class FScript {
@SuppressWarnings("serial")
public static class FScriptException extends RuntimeException {
public FScriptException(String message) {
super(message);
}
}
private String repository;
private String workspace;
private String workspacepassword;
private String logFlags;
private boolean workspaceOpen;
private BufferedWriter toFscript;
private BufferedReader fromFscript;
private BufferedReader errorFscript;
private boolean connectedToFscript = false;
private String forteRoot;
protected Process fscriptProcess;
private boolean justRefreshed = false;
protected RepositorySession session;
protected boolean useSession = false;
private static final String USE_SESSION =
"Tool/debug/useSession";
private static final String CONSOLE_NAME = "Repository Interface";
protected MessageConsole msgConsole;
protected MessageConsoleStream msgStream;
/**
* This class is designed to redirect the contents of a file to a new processes standard input. Note
* that the new process accepts the input, and hence gives us an output stream we write to in this
* process, which will become an input stream (or similar) in the new child process.
* @author Tim
*/
public static class OutputStreamHandler implements Runnable {
private OutputStream stream;
private String command;
public OutputStreamHandler(OutputStream stream, String command) {
this.stream = stream;
this.command = command;
}
public void run() {
try {
// Wait for there to be input in the container
BufferedOutputStream bos = new BufferedOutputStream(stream);
bos.write(command.getBytes());
bos.close();
}
catch (IOException e) {
ToolPlugin.log(IStatus.ERROR,"Error redirecting input to new process.", e);
}
}
}
public FScript(String forteRoot){
super();
this.forteRoot = forteRoot;
this.msgConsole = ToolPlugin.findConsole(CONSOLE_NAME);
if (this.msgConsole != null)
msgStream = msgConsole.newMessageStream();
//String sessionOption = Platform.getDebugOption(USE_SESSION);
//this.useSession = ToolPlugin.getDefault().isDebugging() && "true".equalsIgnoreCase(sessionOption);
}
public FScript(String forteRoot, String repository, String workspace, String workspacePassword, String logFlags, boolean useSession){
this(forteRoot);
this.repository = repository;
this.workspace = workspace;
this.workspacepassword = workspacePassword;
this.logFlags = logFlags;
this.useSession = useSession;
}
protected void writeToConsole(String message){
if (this.msgStream != null)
this.msgStream.println(message);
}
public String processFscriptCommand(String fscriptCMD) throws ToolSystemException{
String result = "";
try {
String cmd = "";
String osName = System.getProperty("os.name");
if (osName.startsWith("Windows")){
cmd = "cmd.exe /C ";
} else {
writeToConsole("Connection to a repository is only possible on a windows platform");
return "";
}
IPath ftExecPath = new Path(this.forteRoot);
ftExecPath = ftExecPath.append("install");
ftExecPath = ftExecPath.append("bin");
ftExecPath = ftExecPath.append("ftexec");
IPath fscriptPath = new Path(this.forteRoot);
fscriptPath = fscriptPath.append("userapp");
fscriptPath = fscriptPath.append("fscript");
fscriptPath = fscriptPath.append("cl12");
fscriptPath = fscriptPath.append("fscript");
cmd = cmd + ftExecPath.toPortableString() + " -fcons -fnict -fi bt:"+ fscriptPath.toPortableString() + " -fs -fr " + repository + " -fw " + workspace + " -fl " + this.logFlags;
fscriptProcess = Runtime.getRuntime().exec(cmd);
// Start readers to consume output. It looks very innocuous with the output from the process
// being mapped to p.inputStream, but this is correct.
OutputContainer container = new OutputContainer(this.msgStream);
new Thread(new InputStreamHandler(fscriptProcess.getInputStream(), container, false), "OutputFileHandler").start();
new Thread(new InputStreamHandler(fscriptProcess.getErrorStream(), container, true), "ErrorFileHandler").start();
new Thread(new OutputStreamHandler(fscriptProcess.getOutputStream(), fscriptCMD), "InputFileHandler").start();
fscriptProcess.waitFor();
this.connectedToFscript = true;
if (container.stderr.length() > 0) {
throw new FScriptException(container.stderr.toString());
}
else {
result = container.stdout.toString();
if (result.contains("SYSTEM ERROR")){
String errorText = result.substring(result.indexOf("SYSTEM ERROR"));
throw new ToolSystemException(getRepository(), errorText);
}
}
} catch (IOException e) {
ToolPlugin.showError("Error connecting to fscript.", e);
} catch (InterruptedException e) {
ToolPlugin.showError("Error connecting to fscript.", e);
}
return result;
}
public void disconnect(){
try {
if (fromFscript != null){
fromFscript.close();
fromFscript = null;
}
if (fromFscript != null){
fromFscript.close();
}
if (errorFscript != null){
errorFscript.close();
}
if (fscriptProcess != null){
fscriptProcess.waitFor();
fscriptProcess = null;
}
} catch (IOException e) {
ToolPlugin.log(IStatus.ERROR,"Error disconnecting from fscript.", e);
} catch (InterruptedException e) {
ToolPlugin.log(IStatus.ERROR,"Error disconnecting from fscript.", e);
} finally {
this.connectedToFscript = false;
}
}
public String SCMExportWorkspace(String directory) throws InvalidToolRepositoryException, ToolSystemException{
if (!isValid()){
throw new InvalidToolRepositoryException(getRepository());
}
writeToConsole("SCMExportWorkspace " + directory );
String command = "open\r\n" +
"SCMExportWork " + directory + "\r\n" +
"exit\r\n";
String result = processFscriptCommand(command);
disconnect();
return result;
}
public String CompilePlanComponent(String plan, String file) throws InvalidToolRepositoryException, ToolSystemException{
if (!isValid()){
throw new InvalidToolRepositoryException(getRepository());
}
writeToConsole("CompilePlanComponent " + plan + "." + file);
String command = "open\r\n" +
"findPlan " + plan + "\r\n" +
"Compile " + file + "\r\n" +
"commit\r\n" +
"exit\r\n";
String result = processFscriptCommand(command);
disconnect();
return result;
}
public String[] ListPlans(boolean pIncludeSystem,
boolean pIncludeLibraries,
boolean Topo,
boolean pIncludeInternal) throws InvalidToolRepositoryException, ToolSystemException{
if (!isValid()){
throw new InvalidToolRepositoryException(getRepository());
}
writeToConsole("ListPlans");
String[] names = null;
String command = "open\r\n" +
"ListProj\r\n" +
"exit\r\n";
String result = processFscriptCommand(command);
disconnect();
result = result.substring(result.indexOf("Projects:"), result.lastIndexOf("fscript"));
String[] lines = result.split("\r\n");
names = new String[lines.length-1];
for (int i = 1; i < lines.length; i++){
names[i-1] = lines[i].trim();
}
// }
return names;
}
public String[] ListWorkspaces() throws ToolSystemException, InvalidToolRepositoryException {
writeToConsole("ListWorkspaces");
String command = "Listwork\r\n" +
"exit\r\n";
String result = processFscriptCommand(command);
disconnect();
result = result.substring(result.indexOf("Available workspaces:"), result.lastIndexOf("fscript"));
String[] lines = result.split("\r\n");
String[] names = new String[lines.length-1];
for (int i = 1; i < lines.length; i++){
names[i-1] = lines[i].trim();
}
return names;
// }
}
public String executeCMD(String command) throws ToolSystemException, InvalidToolRepositoryException {
writeToConsole("executeCMD");
String result = processFscriptCommand(command);
disconnect();
return result;
}
public void close() {
if (this.session != null){
try {
this.session.closeWorkspace();
this.session.closeRepository();
} catch (NotConnectedException e) {
ToolPlugin.showError("Error closing Tool Respository", e);
} catch (CommandException e) {
ToolPlugin.showError("Error closing Tool Respository", e);
}
}
}
public String ShowPlan(String planName) throws InvalidToolRepositoryException, ToolSystemException{
if (!isValid()){
throw new InvalidToolRepositoryException(getRepository());
}
writeToConsole("ShowPlan " + planName);
String command = "open\r\n" +
"FindProj " + planName + "\r\n" +
"ShowPlan\r\n" +
"close\r\n" +
"exit\r\n";
String result = processFscriptCommand(command);
writeToConsole("ShowPlan output:\n" + result);
int start = result.indexOf("Project:");
int end = result.lastIndexOf("fscript");
writeToConsole("Start: " + start + " End: " + end);
result = result.substring(start, end);
disconnect();
return result;
}
private static final String PROJECT_REGEX = "(?s)Application Type: USER.+Portable 4GL scope(?-s)";
private static Pattern isProjectpattern = Pattern.compile(PROJECT_REGEX, Pattern.MULTILINE);
public boolean isProject(String planName) throws InvalidToolRepositoryException, ToolSystemException{
if (isForteLibrary(planName))
return false;
String planText = ShowPlan(planName);
Matcher matcher = isProjectpattern.matcher(planText);
boolean isProject = matcher.find();
return isProject;
}
public boolean isForteLibrary(String name){
boolean isForte = false;
for (String libName : ToolProjectSupport.forteLibrariesList){
if (libName.equalsIgnoreCase(name)){
isForte = true;
break;
}
}
return isForte;
}
public String exportForteLibraries(String directory) throws InvalidToolRepositoryException, ToolSystemException{
if (!isValid()){
throw new InvalidToolRepositoryException(getRepository());
}
writeToConsole("exportForteLibraries to " + directory);
StringBuilder sb = new StringBuilder("open\r\n");
for (String libName : ToolProjectSupport.forteLibrariesList){
sb.append("FindPlan ");
sb.append(libName);
sb.append("\r\n");
sb.append("ExportPlan ");
sb.append(directory);
sb.append("\\");
sb.append(libName);
sb.append(".pex\r\n");
}
sb.append("exit\r\n");
String command = sb.toString();
String result = processFscriptCommand(command);
disconnect();
return result;
}
public String exportAsPEX(String planName, String file) throws ToolRepositoryException {
if (!isValid()){
throw new InvalidToolRepositoryException(getRepository());
}
writeToConsole("exportAsPEX " + planName + " to " + file);
String command = "open\r\n" +
"FindPlan " + planName + "\r\n" +
"ExportPlan " + file + ".pex\r\n" +
"exit\r\n";
String result = processFscriptCommand(command);
disconnect();
return result;
}
// public String exportProject(String planName, String directory) throws InvalidToolRepositoryException, NotConnectedException, CommandException{
// if (!isValid()){
// throw new InvalidToolRepositoryException(getRepository());
// }
// writeToConsole("ExportProject " + planName + " to " + directory);
// RepositorySession session = getSession();
// String result = session.exportPlanAndComponents(planName, directory, true);
// return result;
// }
public String SCMExportProject(String planName, String directory) throws InvalidToolRepositoryException, ToolSystemException {
if (!isValid()){
throw new InvalidToolRepositoryException(getRepository());
}
writeToConsole("SCMExportProject " + planName + " to " + directory);
String command = "open\r\n" +
"findplan " + planName + "\r\n" +
"SCMExportProject " + directory + " all\r\n" +
"exit\r\n";
String result = processFscriptCommand(command);
disconnect();
return result;
}
/**
* runs a specified plan in the repository.
* It is run through fscript in stand-alone mode and as a separate process
* @param planName
* @return
* @throws ToolRepositoryException
*/
public String runPlan(String planName) throws ToolRepositoryException {
if (!isValid()){
throw new InvalidToolRepositoryException(getRepository());
}
writeToConsole("runPlan " + planName + " in Working Directory " + System.getProperty("user.dir", ""));
String command = "open\r\n" +
"FindPlan " + planName + "\r\n" +
"run\r\n" +
"exit\r\n";
String result = processFscriptCommand(command);
disconnect();
return result;
}
public String getRepository() {
return repository;
}
public String getWorkspace() {
return workspace;
}
public boolean isWorkspaceOpen() {
return workspaceOpen;
}
public boolean isValid(){
String osName = System.getProperty("os.name");
if (!osName.startsWith("Windows")){
return false;
}
return (this.repository != null && !this.repository.isEmpty()) &&
(this.workspace!= null && !this.workspace.isEmpty());
}
public boolean isJustRefreshed() {
return justRefreshed;
}
public void setJustRefreshed(boolean justRefreshed) {
this.justRefreshed = justRefreshed;
}
protected void finalize() throws Throwable {
if (this.session != null){
this.session.terminate();
}
};
/**
* Terminates the operating system process running fscript
*/
public void kill(){
if (this.fscriptProcess != null)
this.fscriptProcess.destroy();
}
public static void main(String args[]){
FScript r = new FScript("c:\\APPS\\forte_peter");
// r.repository = "bt:C:\\APPS\\Forte_peter\\repos\\pmilne_star_dev_6";
// r.workspace = "pmilne_star_dev_6";
r.repository = "bt:C:\\APPS\\Forte_peter\\repos\\Tests";
r.workspace = "empty";
r.logFlags = ToolProjectSupport.DEFAULT_LOG_FLAGS;
try {
// String[] ws = r.ListWorkspaces();
String[] plans = r.ListPlans(false, false, false, false);
// for (String planName : plans){
// if (r.isProject(planName)){
// String dir = "C:\\APPS\\DummyProject\\Projects\\" + planName;
// new File(dir).mkdirs();
// r.SCMExportProject(planName, dir);
// } else {
// String dir = "C:\\APPS\\DummyProject\\Libraries\\" + planName;
// r.exportAsPEX(planName, dir);
// }
// }
r.exportForteLibraries("C:\\APPS\\DummyProject\\Libraries");
} catch (InvalidToolRepositoryException e) {
ToolPlugin.showError("Error testing Tool Respository", e);
} catch (ToolSystemException e) {
ToolPlugin.showError("Error testing Tool Respository", e);
} catch (ToolRepositoryException e) {
ToolPlugin.showError("Error testing Tool Respository", e);
}
}
/**
* create a command string using a string template
* @param repos
* @param workspace
* @param wexPath
* @return
*/
public String createCommand(String templateFileName, String templateNam, TemplateAttribute ... attributes){
FileReader reader;
File templateFile;
String output = "";
try {
URL url = Platform.getBundle(ToolPlugin.PLUGIN_ID).getEntry("StringTemplates/Tool/" + templateFileName);
templateFile = new File(FileLocator.toFileURL(url).toURI());
reader = new FileReader(templateFile);
StringTemplateGroup templates = new StringTemplateGroup(reader);
StringTemplate wexTemplate = templates.lookupTemplate(templateNam);
for (TemplateAttribute att : attributes){
wexTemplate.setAttribute(att.name, att.value);
}
output = wexTemplate.toString();
} catch (FileNotFoundException e) {
reportError(e);
} catch (URISyntaxException e) {
reportError(e);
} catch (IOException e) {
reportError(e);
}
return output;
}
protected void reportError(Throwable e){
if (ToolPlugin.getDefault() != null)
ToolPlugin.showError("Error running Fscript", e);
else
e.printStackTrace();
}
}