| /******************************************************************************* |
| * Copyright (c) 2009, 2018 R.Dvorak and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * Radek Dvorak - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.m2m.qvt.oml.debug.core.app; |
| |
| import java.io.IOException; |
| import java.io.ObjectOutputStream; |
| import java.net.ServerSocket; |
| import java.net.Socket; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.m2m.qvt.oml.debug.core.DebugOptions; |
| import org.eclipse.m2m.qvt.oml.debug.core.QVTODebugCore; |
| import org.eclipse.m2m.qvt.oml.debug.core.vm.IQVTOVirtualMachineShell; |
| import org.eclipse.m2m.qvt.oml.debug.core.vm.protocol.VMEvent; |
| import org.eclipse.m2m.qvt.oml.debug.core.vm.protocol.VMTerminateEvent; |
| |
| class VMEventDispatcher { |
| |
| interface TerminationListener { |
| void terminated(); |
| } |
| |
| private final class DispatchJob implements Runnable { |
| private final Object startLock; |
| private final int fPort; |
| private boolean fReady; |
| private boolean fRunning; |
| |
| |
| DispatchJob(int port) { |
| this.startLock = new Object(); |
| fPort = port; |
| fReady = false; |
| fRunning = false; |
| } |
| |
| public void run() { |
| QVTODebugCore.TRACE.trace(DebugOptions.VM, |
| "VM Server Event Dispatcher started"); |
| |
| ObjectOutputStream eventStream = null; |
| ServerSocket serverSocket = null; |
| Socket eventSocket = null; |
| |
| try { |
| synchronized (startLock) { |
| fReady = true; |
| startLock.notify(); |
| } |
| |
| serverSocket = new ServerSocket(fPort); |
| eventSocket = serverSocket.accept(); |
| |
| QVTODebugCore.TRACE.trace(DebugOptions.VM, |
| "VM Server Event Dispatcher accepted connection"); |
| |
| eventStream = new ObjectOutputStream(eventSocket.getOutputStream()); |
| |
| doRun(eventStream); |
| |
| } catch(IOException e) { |
| e.printStackTrace(); |
| // TODO - failed to initialize |
| QVTODebugCore.log(e); |
| |
| } finally { |
| if(eventStream != null) { |
| SocketUtil.close(eventStream); |
| } |
| |
| if(eventSocket != null) { |
| SocketUtil.close(eventSocket); |
| } |
| |
| if(serverSocket != null) { |
| SocketUtil.close(serverSocket); |
| } |
| } |
| } |
| |
| private void doRun(ObjectOutputStream eventStream) { |
| IQVTOVirtualMachineShell vm; |
| // FIXME |
| try { |
| vm = fVMProvider.getVM(); |
| } catch (CoreException e) { |
| // Note: we are not to report this issues, just one of the clients waiting for |
| // the VM initialization on background |
| QVTODebugCore.TRACE.trace(DebugOptions.VM, |
| "VM Server Event dispatcher exiting, VM failed not available"); //$NON-NLS-1$ |
| return; |
| } |
| |
| fRunning = true; |
| |
| while (fRunning) { |
| VMEvent event = null; |
| try { |
| event = vm.readVMEvent(); |
| } catch (IOException e) { |
| QVTODebugCore.TRACE.trace(DebugOptions.VM, |
| "VM Server Event dispatcher interrupted"); //$NON-NLS-1$ |
| } |
| |
| if (event != null) { |
| QVTODebugCore.TRACE.trace(DebugOptions.VM, |
| "VM Server - sending VM event: " + event); //$NON-NLS-1$ |
| |
| try { |
| eventStream.writeObject(event); |
| eventStream.flush(); |
| } catch (IOException e) { |
| // TODO |
| e.printStackTrace(); |
| } |
| } |
| |
| if(event == null || event instanceof VMTerminateEvent) { |
| // Note: VMTerminate has already been sent, we can exit |
| fRunning = false; |
| fReady = false; |
| terminated(); |
| continue; |
| } |
| } |
| |
| QVTODebugCore.TRACE.trace(DebugOptions.VM, |
| "VM Server Event dispather terminated"); //$NON-NLS-1$ |
| } |
| |
| private void waitToReachAccept() { |
| synchronized (startLock) { |
| while(!fReady) { |
| try { |
| startLock.wait(); |
| } catch (InterruptedException e) { |
| // nothing |
| } |
| } |
| } |
| } |
| } |
| |
| private VMProvider fVMProvider; |
| private Thread fDispatchThread; |
| private DispatchJob fDispatchJob; |
| private TerminationListener fTerminationListener; |
| |
| VMEventDispatcher(VMProvider vmProvider, int port, TerminationListener listener) { |
| fDispatchJob = new DispatchJob(port); |
| fTerminationListener = listener; |
| fVMProvider = vmProvider; |
| } |
| |
| protected void terminated() { |
| if(fTerminationListener != null) { |
| try { |
| fTerminationListener.terminated(); |
| } catch(Throwable e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
| |
| void start() { |
| synchronized (this) { |
| if(fDispatchThread != null) { |
| throw new IllegalStateException("Dispatcher already started"); //$NON-NLS-1$ |
| } |
| |
| fDispatchThread = new Thread(fDispatchJob, "QVTO Srv-VMEvent dispatch"); //$NON-NLS-1$ |
| } |
| |
| fDispatchThread.setDaemon(true); |
| fDispatchThread.start(); |
| |
| fDispatchJob.waitToReachAccept(); |
| |
| QVTODebugCore.TRACE.trace(DebugOptions.VM, |
| "VM Server Event dispatcher ready"); //$NON-NLS-1$ |
| } |
| |
| boolean joinTermination(long timeOut) { |
| try { |
| fDispatchThread.join(timeOut); |
| } catch (InterruptedException e) { |
| Thread.interrupted(); |
| } |
| return !fDispatchThread.isAlive(); |
| } |
| |
| } |