EA-29052 - EE: RemoteProcessSupport.acquire

This commit is contained in:
Gregory.Shrago
2012-07-06 19:11:14 +04:00
parent 0ea5de7a9d
commit 133f6a84df
@@ -55,8 +55,7 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
public static final Logger LOG = Logger.getInstance("#" + RemoteProcessSupport.class);
private final Class<EntryPoint> myValueClass;
private final HashMap<Pair<Target, Parameters>, Object> myProcMap =
new HashMap<Pair<Target, Parameters>, Object>();
private final HashMap<Pair<Target, Parameters>, Info> myProcMap = new HashMap<Pair<Target, Parameters>, Info>();
static {
RemoteServer.setupRMI();
@@ -78,13 +77,11 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
}
public void stopAll(boolean wait) {
final ArrayList<ProcessHandler> allHandlers = new ArrayList<ProcessHandler>();
ArrayList<ProcessHandler> allHandlers = new ArrayList<ProcessHandler>();
synchronized (myProcMap) {
for (Object o : myProcMap.values()) {
final ProcessHandler handler = o instanceof PendingInfo ? ((PendingInfo)o).handler : o instanceof Info ? ((Info)o).handler : null;
ContainerUtil.addIfNotNull(handler, allHandlers);
for (Info o : myProcMap.values()) {
ContainerUtil.addIfNotNull(o.handler, allHandlers);
}
myProcMap.clear();
}
for (ProcessHandler handler : allHandlers) {
handler.destroyProcess();
@@ -97,7 +94,7 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
}
public List<Parameters> getActiveConfigurations(@NotNull Target target) {
final ArrayList<Parameters> result = new ArrayList<Parameters>();
ArrayList<Parameters> result = new ArrayList<Parameters>();
synchronized (myProcMap) {
for (Pair<Target, Parameters> pair : myProcMap.keySet()) {
if (pair.first == target) {
@@ -108,11 +105,11 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
return result;
}
public EntryPoint acquire(@NotNull final Target target, @NotNull final Parameters configuration) throws Exception {
public EntryPoint acquire(@NotNull Target target, @NotNull Parameters configuration) throws Exception {
ApplicationManagerEx.getApplicationEx().assertTimeConsuming();
final Ref<Info> ref = Ref.create(null);
final Pair<Target, Parameters> key = Pair.create(target, configuration);
Ref<RunningInfo> ref = Ref.create(null);
Pair<Target, Parameters> key = Pair.create(target, configuration);
if (!getExistingInfo(ref, key)) {
startProcess(target, configuration, key);
if (ref.isNull()) {
@@ -131,38 +128,28 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
}
}
if (ref.isNull()) throw new RuntimeException("Unable to acquire remote proxy for: " + getName(target));
final Info info = ref.get();
RunningInfo info = ref.get();
if (info.handler == null) throw new ExecutionException(info.name);
return acquire(info);
}
public void release(@NotNull Target target, @Nullable Parameters configuration) {
final ArrayList<ProcessHandler> handlersToStop = new ArrayList<ProcessHandler>();
final ArrayList<Pair<Target, Parameters>> keysToRemove = new ArrayList<Pair<Target, Parameters>>();
ArrayList<ProcessHandler> handlers = new ArrayList<ProcessHandler>();
synchronized (myProcMap) {
for (Pair<Target, Parameters> pair : myProcMap.keySet()) {
if (pair.first == target && (configuration == null || pair.second == configuration)) {
final Object o = myProcMap.get(pair);
final ProcessHandler handler = o instanceof PendingInfo ? ((PendingInfo)o).handler : o instanceof Info ? ((Info)o).handler : null;
if (handler != null) {
handlersToStop.add(handler);
keysToRemove.add(pair);
}
else {
// todo what to do???
}
ContainerUtil.addIfNotNull(myProcMap.get(pair).handler, handlers);
}
}
myProcMap.keySet().removeAll(keysToRemove);
}
for (ProcessHandler handler : handlersToStop) {
for (ProcessHandler handler : handlers) {
handler.destroyProcess();
}
fireModificationCountChanged();
}
private void startProcess(Target target, Parameters configuration, Pair<Target, Parameters> key) {
final ProgramRunner runner = new DefaultProgramRunner() {
ProgramRunner runner = new DefaultProgramRunner() {
@NotNull
public String getRunnerId() {
return "MyRunner";
@@ -172,16 +159,16 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
return true;
}
};
final Executor executor = DefaultRunExecutor.getRunExecutorInstance();
ProcessHandler processHandler;
Executor executor = DefaultRunExecutor.getRunExecutorInstance();
ProcessHandler processHandler = null;
try {
final RunProfileState state = getRunProfileState(target, configuration, executor);
final ExecutionResult result = state.execute(executor, runner);
RunProfileState state = getRunProfileState(target, configuration, executor);
ExecutionResult result = state.execute(executor, runner);
//noinspection ConstantConditions
processHandler = result.getProcessHandler();
}
catch (Exception e) {
handleProcessTerminated(key, ExceptionUtil.getUserStackTrace(e, LOG));
dropProcessInfo(key, ExceptionUtil.getUserStackTrace(e, LOG), processHandler);
return;
}
processHandler.addProcessListener(getProcessListener(key));
@@ -191,13 +178,14 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
protected abstract RunProfileState getRunProfileState(Target target, Parameters configuration, Executor executor)
throws ExecutionException;
private boolean getExistingInfo(Ref<Info> ref, final Pair<Target, Parameters> key) {
Object info;
private boolean getExistingInfo(Ref<RunningInfo> ref, Pair<Target, Parameters> key) {
Info info;
synchronized (myProcMap) {
info = myProcMap.get(key);
try {
while (info != null &&
(!(info instanceof Info) || ((Info)info).handler.isProcessTerminating() || ((Info)info).handler.isProcessTerminated())) {
while (info != null && (!(info instanceof RunningInfo) ||
info.handler.isProcessTerminating() ||
info.handler.isProcessTerminated())) {
myProcMap.wait(1000);
ProgressManager.checkCanceled();
info = myProcMap.get(key);
@@ -210,24 +198,21 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
myProcMap.put(key, new PendingInfo(ref, null));
}
}
if (info != null) {
if (info instanceof Info) {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (ref) {
ref.set((Info)info);
ref.notifyAll();
}
if (info instanceof RunningInfo) {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (ref) {
ref.set((RunningInfo)info);
ref.notifyAll();
}
return true;
}
return false;
return info != null;
}
private EntryPoint acquire(final Info port) throws Exception {
final EntryPoint result = RemoteUtil.executeWithClassLoader(new ThrowableComputable<EntryPoint, Exception>() {
private EntryPoint acquire(final RunningInfo port) throws Exception {
EntryPoint result = RemoteUtil.executeWithClassLoader(new ThrowableComputable<EntryPoint, Exception>() {
public EntryPoint compute() throws Exception {
final Registry registry = LocateRegistry.getRegistry("localhost", port.port);
final Remote remote = registry.lookup(port.name);
Registry registry = LocateRegistry.getRegistry("localhost", port.port);
Remote remote = registry.lookup(port.name);
if (Remote.class.isAssignableFrom(myValueClass)) {
return RemoteUtil.substituteClassLoader(narrowImpl(remote, myValueClass), myValueClass.getClassLoader());
}
@@ -249,9 +234,9 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
private ProcessListener getProcessListener(final Pair<Target, Parameters> key) {
return new ProcessListener() {
public void startNotified(ProcessEvent event) {
final ProcessHandler processHandler = event.getProcessHandler();
ProcessHandler processHandler = event.getProcessHandler();
processHandler.putUserData(ProcessHandler.SILENTLY_DESTROY_ON_CLOSE, Boolean.TRUE);
final Object o;
Info o;
synchronized (myProcMap) {
o = myProcMap.get(key);
if (o instanceof PendingInfo) {
@@ -261,15 +246,19 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
}
public void processTerminated(ProcessEvent event) {
handleProcessTerminated(key, null);
fireModificationCountChanged();
if (dropProcessInfo(key, null, event.getProcessHandler())) {
fireModificationCountChanged();
}
}
public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
if (dropProcessInfo(key, null, event.getProcessHandler())) {
fireModificationCountChanged();
}
}
public void onTextAvailable(ProcessEvent event, Key outputType) {
final String text = StringUtil.notNullize(event.getText());
String text = StringUtil.notNullize(event.getText());
if (outputType == ProcessOutputTypes.STDERR) {
LOG.warn(text.trim());
}
@@ -277,19 +266,19 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
LOG.info(text.trim());
}
Info result = null;
final PendingInfo info;
RunningInfo result = null;
PendingInfo info;
synchronized (myProcMap) {
final Object o = myProcMap.get(key);
Info o = myProcMap.get(key);
logText(key.second, event, outputType, o);
if (o instanceof PendingInfo) {
info = (PendingInfo)o;
if (outputType == ProcessOutputTypes.STDOUT) {
final String prefix = "Port/ID:";
String prefix = "Port/ID:";
if (text.startsWith(prefix)) {
final String pair = text.substring(prefix.length()).trim();
final int idx = pair.indexOf("/");
result = new Info(info.handler, Integer.parseInt(pair.substring(0, idx)), pair.substring(idx + 1));
String pair = text.substring(prefix.length()).trim();
int idx = pair.indexOf("/");
result = new RunningInfo(info.handler, Integer.parseInt(pair.substring(0, idx)), pair.substring(idx + 1));
myProcMap.put(key, result);
myProcMap.notifyAll();
}
@@ -319,44 +308,58 @@ public abstract class RemoteProcessSupport<Target, EntryPoint, Parameters> {
};
}
private void handleProcessTerminated(Pair<Target, Parameters> key, @Nullable String errorMessage) {
Object o;
final PendingInfo pendingInfo;
private boolean dropProcessInfo(Pair<Target, Parameters> key, @Nullable String errorMessage, @Nullable ProcessHandler handler) {
Info info;
synchronized (myProcMap) {
o = myProcMap.remove(key);
pendingInfo = o instanceof PendingInfo ? (PendingInfo)o : null;
if (pendingInfo != null && (pendingInfo.stderr.length() > 0 || pendingInfo.ref.isNull())) {
if (errorMessage != null) pendingInfo.stderr.append(errorMessage);
pendingInfo.ref.set(new Info(null, -1, pendingInfo.stderr.toString()));
info = myProcMap.get(key);
if (info != null && info.handler != null && info.handler == handler) {
myProcMap.remove(key);
myProcMap.notifyAll();
}
else {
// different processHandler
info = null;
}
myProcMap.notifyAll();
}
if (pendingInfo != null) {
if (info instanceof PendingInfo) {
PendingInfo pendingInfo = (PendingInfo)info;
if (pendingInfo.stderr.length() > 0 || pendingInfo.ref.isNull()) {
if (errorMessage != null) pendingInfo.stderr.append(errorMessage);
pendingInfo.ref.set(new RunningInfo(null, -1, pendingInfo.stderr.toString()));
}
synchronized (pendingInfo.ref) {
pendingInfo.ref.notifyAll();
}
}
}
private static class PendingInfo {
final Ref<Info> ref;
final ProcessHandler handler;
final StringBuilder stderr = new StringBuilder();
private PendingInfo(Ref<Info> ref, ProcessHandler handler) {
this.ref = ref;
this.handler = handler;
}
return info != null;
}
private static class Info {
final ProcessHandler handler;
Info(ProcessHandler handler) {
this.handler = handler;
}
}
private static class PendingInfo extends Info {
final Ref<RunningInfo> ref;
final StringBuilder stderr = new StringBuilder();
PendingInfo(Ref<RunningInfo> ref, ProcessHandler handler) {
super(handler);
this.ref = ref;
}
}
private static class RunningInfo extends Info {
final int port;
final String name;
Object entryPointHardRef;
private Info(ProcessHandler handler, int port, String name) {
this.handler = handler;
RunningInfo(ProcessHandler handler, int port, String name) {
super(handler);
this.port = port;
this.name = name;
}