package tool.repository;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchListener;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;
import tool.ToolPlugin;
import tool.ToolProjectSupport;
import tool.builder.PlanDetail;
public class RepositorySession {
protected static final String REPOS_INTERFACE_LOG_FLAGS = ToolProjectSupport.DEFAULT_LOG_FLAGS;
protected static final String SEPERATOR = "|";
private static final int BUFFER_SIZE = 2048;
private static final int PORT_NUMBER = 15001;
private Socket commsSocket;
private ServerSocket serverSocket;
private boolean connected = false;
private BufferedReader in;
private BufferedWriter out;
private String EOS_MARKER = "<EOS>";
private StringBuilder buffer = new StringBuilder(BUFFER_SIZE);
private char[] charBuf = new char[BUFFER_SIZE];
private boolean terminating;
private Process reposProcess;
private static final String PLAN_DETAIL_REGEX = "([a-zA-Z0-9]+)\\|isLibrary=(true|false|TRUE|FALSE)\\|isSystemLibrary=(true|false|TRUE|FALSE)";
private static final Pattern planDetailPattern = Pattern.compile(PLAN_DETAIL_REGEX);
private static final String CONSOLE_NAME = "Repository Session";
private static final String INTERFACE_CONSOLE_NAME = "Repository Interface";
protected MessageConsole msgConsole;
protected MessageConsoleStream msgStream;
protected MessageConsole interfaceConsole;
protected MessageConsoleStream interfaceStream;
private String repository;
private String workspace;
private String workspacePassword;
private boolean justRefreshed = false;
private boolean repositoryOpen;
private boolean workspaceOpen;
/**
* locate a connection to a RepositorySession by obtaining a
* previously located RepositorySession from a session property on the Project
* OR
* create a new one and add it to the session property
*
* @param project
* @return
*/
public static RepositorySession getRepositorySession(IProject project){
RepositorySession repos = null;
try {
repos = (RepositorySession)project.getSessionProperty(new QualifiedName(ToolProjectSupport.PROJECT_QUALIFIED_NAME, ToolProjectSupport.REPOS_SESSION_OBJECT));
if (repos == null){
/*
* create a RepositorySession based on the project properties
* and store it as a session property
*/
String repository = project.getPersistentProperty(ToolProjectSupport.reposQualifiedName);
String workspace = project.getPersistentProperty(ToolProjectSupport.workspaceQualifiedName);
String workspacePassword = project.getPersistentProperty(ToolProjectSupport.worspacePasswordQualifiedName);
File reposDir = ToolProjectSupport.getInterfaceDir();
IPath interfacePath = new Path(reposDir.getAbsolutePath());
repos = new RepositorySession(repository, workspace, workspacePassword, interfacePath, project);
project.setSessionProperty(new QualifiedName(ToolProjectSupport.PROJECT_QUALIFIED_NAME, ToolProjectSupport.REPOS_SESSION_OBJECT), repos);
}
} catch (CoreException e) {
ToolPlugin.showError("Cannot connect to Repository session", e);
} catch (CouldNotConnectException e) {
ToolPlugin.showError("Cannot connect to Repository session", e);
} catch (URISyntaxException e) {
ToolPlugin.showError("Cannot connect to Repository session", e);
} catch (IOException e) {
ToolPlugin.showError("Cannot connect to Repository session", e);
}
return repos;
}
/**
* the method creates a connection to the Forte repository by:
* spawning a process that runs ftexec and the image repository.
* @param forteRoot the root directory of a forte installation
* @param logFlags the default log flags
* @param interfacePath the absolute path of the image repository
* @throws CouldNotConnectException
*/
public RepositorySession(IPath interfacePath, IProject project) throws CouldNotConnectException /*throws CouldNotConnectException/*, NotConnectedException, CommandException */{
String port = ToolPlugin.getNextPort();
this.msgConsole = ToolPlugin.findConsole(CONSOLE_NAME);
if (this.msgConsole != null)
msgStream = msgConsole.newMessageStream();
this.interfaceConsole = ToolPlugin.findConsole(INTERFACE_CONSOLE_NAME);
if (this.interfaceConsole != null)
interfaceStream = interfaceConsole.newMessageStream();
try {
String logFlags = "\"RepositoryInterface.log" + REPOS_INTERFACE_LOG_FLAGS + " %stdout" + REPOS_INTERFACE_LOG_FLAGS + "\"";
serverSocket = new ServerSocket(Integer.parseInt(port));
startInterface(logFlags, interfacePath, port);
commsSocket = serverSocket.accept();
in = new BufferedReader(new InputStreamReader(commsSocket.getInputStream()));
out = new BufferedWriter(new OutputStreamWriter(commsSocket.getOutputStream()));
}
catch (IOException e) {
ToolPlugin.showError("Cannot start the Repository interface", e);
}
}
public RepositorySession(String repository,
String workspace, String workspacePassword, IPath interfacePath, IProject project) throws CouldNotConnectException {
this(interfacePath, project);
this.repository = repository;
this.workspace = workspace;
this.workspacePassword = workspacePassword;
IWorkbench workBench = PlatformUI.getWorkbench();
workBench.addWorkbenchListener(new IWorkbenchListener() {
@Override
public boolean preShutdown(IWorkbench workBench, boolean forced) {
try {
closeWorkspace();
closeRepository();
} catch (NotConnectedException e) {
ToolPlugin.log(IStatus.ERROR, "Error closing repository", e);
} catch (CommandException e) {
ToolPlugin.log(IStatus.ERROR, "Error closing repository", e);
}
if (reposProcess != null)
reposProcess.destroy();
return true;
}
@Override
public void postShutdown(IWorkbench workBench) {
}
});
}
protected void writeToConsole(String message){
if (this.msgStream != null)
this.msgStream.println(message);
}
public String[] listPlanNames(boolean pIncludeSystem,
boolean pIncludeLibraries,
boolean Topo,
boolean pIncludeInternal) throws NotConnectedException, CommandException {
String cmdString = "ListProjectNames" + SEPERATOR +
pIncludeSystem + SEPERATOR +
pIncludeLibraries + SEPERATOR +
Topo + SEPERATOR +
pIncludeInternal;
String result = send(cmdString);
return result.split("\\s");
}
public List<PlanDetail> listPlanNamesWithDetails(boolean pIncludeSystem,
boolean pIncludeLibraries,
boolean Topo,
boolean pIncludeInternal) throws NotConnectedException, CommandException {
String cmdString = "ListProjects" + SEPERATOR +
pIncludeSystem + SEPERATOR +
pIncludeLibraries + SEPERATOR +
Topo + SEPERATOR +
pIncludeInternal;
String result = send(cmdString);
String[] results = result.split("\\s+");
List<PlanDetail> planInfo = new ArrayList<PlanDetail>();
for (String line : results){
Matcher matcher = planDetailPattern.matcher(line);
if (matcher.find()){
String name = matcher.group(1);
boolean isLibrary = Boolean.parseBoolean(matcher.group(2));
boolean isSystemLibrary = Boolean.parseBoolean(matcher.group(3));
PlanDetail plan = new PlanDetail(name,
isLibrary,
isSystemLibrary);
if (plan.getName().startsWith("qq"))
continue;
planInfo.add(plan);
}
}
return planInfo;
}
public void exportPlan(String planName, String directoryName, boolean withIds) throws NotConnectedException, CommandException {
String cmdString = "ExportPlan" + SEPERATOR +
planName + SEPERATOR +
directoryName + SEPERATOR + withIds;
send(cmdString);
}
public String exportPlanAndComponents(String planName, String directoryName, boolean withIds) throws NotConnectedException, CommandException {
String cmdString = "ExportPlanAndComponents" + SEPERATOR +
planName + SEPERATOR +
directoryName + SEPERATOR + withIds;
return send(cmdString);
}
public String exportPlanAsPEX(String planName, String directoryName) throws NotConnectedException, CommandException {
String cmdString = "ExportPlanAsPex" + SEPERATOR +
planName + SEPERATOR +
directoryName;
return send(cmdString);
}
public String exportComponent(String planName, String componentName, String directoryName,
boolean withIds) throws NotConnectedException, CommandException {
String cmdString = "ExportComponent" + SEPERATOR +
planName + SEPERATOR +
componentName + SEPERATOR +
directoryName + SEPERATOR + withIds;
return send(cmdString);
}
public String importComponent(String planName, String fileName) throws NotConnectedException, CommandException {
String cmdString = "ExportComponent" + SEPERATOR +
planName + SEPERATOR +
fileName;
return send(cmdString);
}
public String runPlanLocal(String planName, boolean withProfiling) throws NotConnectedException, CommandException {
String cmdString = "RunPlanLocal" + SEPERATOR +
planName + SEPERATOR +
withProfiling;
return send(cmdString);
}
public String cancelRun() throws NotConnectedException, CommandException {
return send("CancelRun");
}
public String[] listWorkspaces() throws NotConnectedException, CommandException {
String result = send("ListWorkspaces");
return result.split("\\s");
}
public String[] listRepositories() throws NotConnectedException, CommandException {
String result = send("ListRepositories");
return result.split("\\s");
}
public void openWorkspace() throws NotConnectedException, CommandException{
openWorkspace(this.workspace);
}
public void openWorkspace(String workspaceName) throws NotConnectedException, CommandException {
send("OpenWorkSpace" + SEPERATOR + workspaceName);
this.workspaceOpen = true;
}
public String compileComponent(String planName, String componentPath) throws NotConnectedException, CommandException {
return send("ImportComponent" + SEPERATOR + planName + SEPERATOR + componentPath);
}
public void openWorkspace(String workspaceName, String password) throws NotConnectedException, CommandException {
send("OpenWorkspace" + SEPERATOR + workspaceName + SEPERATOR + password);
this.workspaceOpen = true;
}
public void closeWorkspace() throws NotConnectedException, CommandException {
send("CloseWorkspace");
this.workspaceOpen = false;
}
public void openRepository(String repositoryName) throws NotConnectedException, CommandException {
send("OpenRepository" + SEPERATOR + repositoryName);
this.repositoryOpen = true;
connected = true;
}
public void openRepository() throws NotConnectedException, CommandException {
openRepository(this.repository);
}
public void closeRepository() throws NotConnectedException, CommandException {
send("CloseRepository");
this.repositoryOpen = false;
connected = false;
}
private String send(String packet) throws NotConnectedException, CommandException {
if (commsSocket != null) {
try {
writeToConsole("-- Sending: '" + packet + "'");
out.append(packet);
out.append(EOS_MARKER);
out.flush();
// Now wait for the response.
buffer.setLength(0);
while (true) {
int len = in.read(charBuf);
if (len < 0) {
// The socket has been closed
writeToConsole("-- Server has closed socket unexpectedly --");
throw new NotConnectedException();
}
buffer.append(charBuf, 0, len);
int index =buffer.indexOf(EOS_MARKER);
if (index >= 0) {
String result = buffer.substring(0, index);
writeToConsole("-- Received: " + result);
if (result.startsWith("EXCEPTION: ")) {
// Do some exception processing
throw new CommandException(result.substring(11));
}
return result;
}
}
}
catch (IOException ioe) {
if (!terminating){
writeToConsole("-- Server closed connection unexpectedly --");
this.terminate();
throw new NotConnectedException();
}
}
}
else {
throw new NotConnectedException();
}
return "";
}
public void terminate() {
try {
if (connected) {
closeRepository();
}
} catch (NotConnectedException e) {
} catch (CommandException e) {
}
try {
commsSocket.close();
} catch (IOException e) {
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
}
}
if (this.reposProcess != null){
this.reposProcess.destroy();
}
}
public String getRepository() {
return repository;
}
public void killInterfaceProcess() throws NotConnectedException, CommandException {
this.terminating = true;
send("Terminate");
this.reposProcess.destroy();
}
public void startInterface(String logFlags, IPath interfacePath, String port) throws NumberFormatException, IOException{
String forteRoot = ToolProjectSupport.getForteRoot();
InetAddress addr = InetAddress.getLocalHost();
String hostName = addr.getHostName();
writeToConsole("-- Starting interface at: " + interfacePath);
ToolPlugin.log(IStatus.INFO, "-- Starting interface at: " + interfacePath);
String osName = System.getProperty("os.name");
if (!osName.startsWith("Windows")){ // Only run it on windows
writeToConsole("-- Can only run the interface on Windows --");
ToolPlugin.log(IStatus.INFO, "-- Can only run the interface on Windows --");
return;
}
IPath ftExecPath = new Path(ToolProjectSupport.getForteRoot());
ftExecPath = ftExecPath.append("install");
ftExecPath = ftExecPath.append("bin");
ftExecPath = ftExecPath.append("ftexec.exe");
IPath imagePath = interfacePath;
imagePath = imagePath.append("reposi0");
ProcessBuilder pb = new ProcessBuilder(ftExecPath.toOSString(),
"-fcons",
"-fnict",
"-fs",
"-fl",
logFlags,
"-fm(x:999000)",
"-fi",
"bt:"+ imagePath.toOSString(),
"-host",
hostName,
"-port",
port);
Map<String, String> env = pb.environment();
env.put("FORTE_ROOT", forteRoot);
ToolPlugin.log(IStatus.INFO, "-- Interface FORTE_ROOT = " + forteRoot);
writeToConsole("-- Interface FORTE_ROOT = " + forteRoot);
//env.put("FORTE_LOGGER_SETUP", logFlags);
//ToolPlugin.log(IStatus.INFO, "-- Interface FORTE_LOGGER_SETUP = " + logFlags);
//writeToConsole("-- Interface FORTE_LOGGER_SETUP = " + logFlags);
pb.directory(interfacePath.toFile());
ToolPlugin.log(IStatus.INFO, "-- Interface working directory = " + interfacePath.toFile().getAbsolutePath());
writeToConsole("-- Interface working directory = " + interfacePath.toFile().getAbsolutePath());
try {
this.reposProcess = pb.start();
ToolPlugin.log(IStatus.INFO, "-- Interface process started --");
writeToConsole("-- Interface process started --");
ToolPlugin.log(IStatus.INFO, "-- Interface CMD line = " + pb.command());
writeToConsole("-- Interface CMD line = " + pb.command());
// 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.interfaceStream);
new Thread(new InputStreamHandler(this.reposProcess.getInputStream(), container, false), "OutputFileHandler").start();
new Thread(new InputStreamHandler(this.reposProcess.getErrorStream(), container, true), "ErrorFileHandler").start();
} catch (IOException e) {
ToolPlugin.showError("Error starting Repository interface", e);
}
}
public static void main(String[] args) {
RepositorySession s = null;
try {
System.out.println("Starting up");
s = new RepositorySession(new Path("E:\\Tool\\ReposInterface"), null);
s.openRepository("bt:C:\\APPS\\ClearCaseViews\\pmilne_star_dev_fusionAug2011\\repos\\pmilne_star_dev_fusionAug2011");
// s.openRepository("bt:e:\\forte\\repos\\demo30");
String[] workspaces = s.listWorkspaces();
for (String workspaceName : workspaces) {
System.out.println(workspaceName);
}
s.openWorkspace("pmilne_star_dev_fusionAug2011");
// s.openWorkspace("firstworkspace");
// String[] planNames = s.listPlanNames(false, false, false, false);
List<PlanDetail> planNames = s.listPlanNamesWithDetails(false, false, false, false);
for (PlanDetail planName : planNames) {
System.out.println(planName);
if (!planName.isSystemLibrary())
s.exportPlanAndComponents(planName.getName(), "c:\\APPS\\Demo30\\" + planName.getName(), true);
}
//s.exportPlan("NavCoreConstants", "c:\\APPS", true);
//s.exportComponent("NavCoreServices", "InvAccTranAssgnmtDBHandler", "c:\\APPS\\NavCoreServices", true);
// s.runPlanLocal("Auction", false);
s.closeWorkspace();
s.closeRepository();
s.terminate();
} catch (CouldNotConnectException e) {
ToolPlugin.showError("Error in Respository session", e);
} catch (NotConnectedException e) {
ToolPlugin.showError("Error in Respository session", e);
} catch (CommandException e) {
ToolPlugin.showError("Error in Respository session", e);
} finally {
try {
if (s != null)
s.finalize();
} catch (NotConnectedException e) {
ToolPlugin.showError("Error in Respository session", e);
} catch (CommandException e) {
ToolPlugin.showError("Error in Respository session", e);
} catch (Throwable e) {
ToolPlugin.showError("Error in Respository session", e);
}
}
}
@Override
protected void finalize() throws Throwable {
if (this.reposProcess != null){
this.reposProcess.destroy();
}
super.finalize();
}
public boolean isJustRefreshed() {
return justRefreshed;
}
public void setJustRefreshed(boolean justRefreshed) {
this.justRefreshed = justRefreshed;
}
public boolean isRepositoryOpen() {
return repositoryOpen;
}
public boolean isWorkspaceOpen() {
return workspaceOpen;
}
}