[#1472] Add a Settings.executeDebugging property, and move

server-side Console logic to core

 - Split CommunicationInterface logic into client/server-side parts
 - Removed unnecessary CommunicationInterfaceFactory
This commit is contained in:
Lukas Eder 2012-09-09 14:01:30 +02:00
parent 46430604bf
commit fdff1108ef
9 changed files with 216 additions and 171 deletions

View File

@ -0,0 +1,80 @@
/**
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
* Christopher Deckers, chrriis@gmail.com
* All rights reserved.
*
* This software is licensed to you under the Apache License, Version 2.0
* (the "License"); You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name "jOOQ" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jooq.debug.console.remote;
import java.io.IOException;
import java.net.Socket;
/**
* @author Lukas Eder
*/
final class ClientCommunication extends Communication {
public ClientCommunication(ClientDebugger debugger, int port, String ip) throws Exception {
super(debugger);
init(port, ip);
}
private void init(int port, String ip) throws Exception {
// Create the interface to communicate with the process handling the
// other side
Socket socket = null;
// 2 attempts
for (int i = 1; i >= 0; i--) {
try {
socket = new Socket(ip, port);
break;
}
catch (IOException e) {
if (i == 0) {
throw new RuntimeException(e);
}
}
try {
Thread.sleep(100);
}
catch (Exception e) {}
}
if (socket == null) {
throw new IllegalStateException("Failed to connect to " + ip + "!");
}
setMessagingInterface(new MessagingInterface(this, socket, true));
notifyOpen();
}
}

View File

@ -67,18 +67,13 @@ import org.jooq.debug.console.remote.ServerDebugger.CMS_setLoggingStatementMatch
@SuppressWarnings("serial")
public class ClientDebugger implements Debugger {
private CommunicationInterface comm;
private Communication comm;
public ClientDebugger(String ip, int port) throws Exception {
comm = CommunicationInterface.openClientCommunicationChannel(new CommunicationInterfaceFactory() {
@Override
public CommunicationInterface createCommunicationInterface(int port_) {
return new CommunicationInterface(ClientDebugger.this, port_);
}
}, ip, port);
comm = new ClientCommunication(this, port, ip);
}
CommunicationInterface getCommunicationInterface() {
Communication getCommunicationInterface() {
return comm;
}

View File

@ -58,7 +58,7 @@ abstract class CommandMessage<S extends Serializable> extends Message<S> {
/**
* Run the message.
*
* @param context The context in which this {@link Message} object is run
* @param context The context in which this <code>Message</code> object is run
* @return the result that may be passed back to the caller.
* @throws Exception any exception that may happen, and which would be
* passed back if it is a synchronous execution.

View File

@ -36,11 +36,7 @@
*/
package org.jooq.debug.console.remote;
import java.io.IOException;
import java.io.Serializable;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import org.jooq.debug.Debugger;
@ -50,17 +46,17 @@ import org.jooq.debug.Debugger;
*
* @author Christopher Deckers
*/
class CommunicationInterface {
abstract class Communication {
private final boolean IS_SYNCING_MESSAGES = Boolean.parseBoolean(System.getProperty("communication.interface.syncmessages"));
private final boolean IS_SYNCING_MESSAGES = Boolean.parseBoolean(System.getProperty("communication.interface.syncmessages"));
private volatile boolean isOpen;
private final Debugger debugger;
private final int port;
private volatile boolean isOpen;
private volatile MessagingInterface messagingInterface;
public CommunicationInterface(Debugger debugger, int port) {
private final Debugger debugger;
public Communication(Debugger debugger) {
this.debugger = debugger;
this.port = port;
}
public Debugger getDebugger() {
@ -72,25 +68,19 @@ class CommunicationInterface {
}
private void checkOpen() {
if(!isOpen()) {
if (!isOpen()) {
throw new IllegalStateException("The interface is not open!");
}
}
public void close() {
isOpen = false;
if(messagingInterface != null) {
if (messagingInterface != null) {
messagingInterface.destroy();
messagingInterface = null;
}
}
public static CommunicationInterface openClientCommunicationChannel(CommunicationInterfaceFactory communicationInterfaceFactory, String ip, int port) throws Exception {
CommunicationInterface communicationInterface = communicationInterfaceFactory.createCommunicationInterface(port);
communicationInterface.createClientCommunicationChannel(ip);
return communicationInterface;
}
void notifyOpen() {
isOpen = true;
processOpened();
@ -108,33 +98,10 @@ class CommunicationInterface {
protected void processClosed() {
}
private void createClientCommunicationChannel(String ip) throws Exception {
// Create the interface to communicate with the process handling the other side
Socket socket = null;
// 2 attempts
for(int i=1; i>=0; i--) {
try {
socket = new Socket(ip, port);
break;
} catch(IOException e) {
if(i == 0) {
throw new RuntimeException(e);
}
}
try {
Thread.sleep(100);
} catch(Exception e) {
}
}
if(socket == null) {
throw new IllegalStateException("Failed to connect to " + ip + "!");
}
messagingInterface = new MessagingInterface(this, socket, true);
notifyOpen();
void setMessagingInterface(MessagingInterface messagingInterface) {
this.messagingInterface = messagingInterface;
}
private volatile MessagingInterface messagingInterface;
MessagingInterface getMessagingInterface() {
return messagingInterface;
}
@ -171,42 +138,4 @@ class CommunicationInterface {
messagingInterface.asyncSend(message);
}
}
public static ServerSocket openServerCommunicationChannel(final CommunicationInterfaceFactory communicationInterfaceFactory, final int port) throws Exception {
final ServerSocket serverSocket;
try {
serverSocket = new ServerSocket();
// serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(port));
} catch(IOException e) {
throw e;
}
Thread serverThread = new Thread("Communication channel server on port " + port) {
@Override
public void run() {
while(!serverSocket.isClosed()) {
final Socket socket;
try {
socket = serverSocket.accept();
new Thread("Communication channel - client connection") {
@Override
public void run() {
CommunicationInterface communicationInterface = communicationInterfaceFactory.createCommunicationInterface(port);
communicationInterface.messagingInterface = new MessagingInterface(communicationInterface, socket, false);
communicationInterface.notifyOpen();
}
}.start();
} catch(Exception e) {
if(!serverSocket.isClosed()) {
e.printStackTrace();
}
}
}
}
};
serverThread.setDaemon(true);
serverThread.start();
return serverSocket;
}
}

View File

@ -51,7 +51,7 @@ class MessageContext {
private final Debugger debugger;
private final MessagingInterface messagingInterface;
public MessageContext(CommunicationInterface comm) {
public MessageContext(Communication comm) {
this(comm.getDebugger(), comm.getMessagingInterface());
}

View File

@ -168,11 +168,11 @@ class MessagingInterface {
private Map<Long, MessageProcessingThread> originatorThreadIDToThreadMap = new HashMap<Long, MessagingInterface.MessageProcessingThread>();
private CommunicationInterface comm;
private Communication comm;
private boolean isClient;
MessagingInterface(final CommunicationInterface communicationInterface, final Socket socket, boolean isClient) {
this.comm = communicationInterface;
MessagingInterface(final Communication communication, final Socket socket, boolean isClient) {
this.comm = communication;
this.isClient = isClient;
try {
oos = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()) {
@ -204,7 +204,7 @@ class MessagingInterface {
isAlive = false;
// e.printStackTrace();
try {
communicationInterface.notifyKilled();
communication.notifyKilled();
} catch(Exception ex) {
ex.printStackTrace();
}

View File

@ -37,9 +37,10 @@
package org.jooq.debug.console.remote;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import org.jooq.debug.DebuggerRegistry;
import org.jooq.debug.console.DatabaseDescriptor;
/**
@ -54,34 +55,16 @@ public class RemoteDebuggerServer {
this(port, null);
}
public RemoteDebuggerServer(final int port, final DatabaseDescriptor descriptor) {
public RemoteDebuggerServer(final int port, final DatabaseDescriptor descriptor) {
try {
synchronized(LOCK) {
serverSocket = CommunicationInterface.openServerCommunicationChannel(new CommunicationInterfaceFactory() {
@Override
public CommunicationInterface createCommunicationInterface(int port_) {
final ServerDebugger debugger = new ServerDebugger(descriptor);
CommunicationInterface commmunicationInterface = new CommunicationInterface(debugger, port_) {
@Override
protected void processOpened() {
DebuggerRegistry.add(debugger);
}
@Override
protected void processClosed() {
DebuggerRegistry.remove(debugger);
debugger.cleanup();
}
};
debugger.setCommunicationInterface(commmunicationInterface);
return commmunicationInterface;
}
}, port);
synchronized (LOCK) {
serverSocket = openServerCommunicationChannel(port, descriptor);
}
} catch(Exception e) {
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public void close() {
synchronized (LOCK) {
@ -96,4 +79,43 @@ public class RemoteDebuggerServer {
}
}
}
public static ServerSocket openServerCommunicationChannel(final int port, final DatabaseDescriptor descriptor) throws Exception {
final ServerSocket serverSocket;
try {
serverSocket = new ServerSocket();
// serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(port));
} catch(IOException e) {
throw e;
}
Thread serverThread = new Thread("Communication channel server on port " + port) {
@Override
public void run() {
while(!serverSocket.isClosed()) {
final Socket socket;
try {
socket = serverSocket.accept();
new Thread("Communication channel - client connection") {
@Override
public void run() {
final ServerDebugger debugger = new ServerDebugger(descriptor);
Communication comm = new ServerCommunication(debugger);
debugger.setCommunicationInterface(comm);
comm.setMessagingInterface(new MessagingInterface(comm, socket, false));
comm.notifyOpen();
}
}.start();
} catch(Exception e) {
if(!serverSocket.isClosed()) {
e.printStackTrace();
}
}
}
}
};
serverThread.setDaemon(true);
serverThread.start();
return serverSocket;
}
}

View File

@ -1,47 +1,66 @@
/**
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
* Christopher Deckers, chrriis@gmail.com
* All rights reserved.
*
* This software is licensed to you under the Apache License, Version 2.0
* (the "License"); You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name "jOOQ" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jooq.debug.console.remote;
/**
* @author Christopher Deckers
*/
interface CommunicationInterfaceFactory {
public CommunicationInterface createCommunicationInterface(int port);
}
/**
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
* Christopher Deckers, chrriis@gmail.com
* All rights reserved.
*
* This software is licensed to you under the Apache License, Version 2.0
* (the "License"); You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name "jOOQ" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jooq.debug.console.remote;
import org.jooq.debug.DebuggerRegistry;
/**
* @author Lukas Eder
*/
final class ServerCommunication extends Communication {
public ServerCommunication(ServerDebugger debugger) {
super(debugger);
}
@Override
public ServerDebugger getDebugger() {
return (ServerDebugger) super.getDebugger();
}
@Override
protected void processOpened() {
DebuggerRegistry.add(getDebugger());
}
@Override
protected void processClosed() {
DebuggerRegistry.remove(getDebugger());
getDebugger().cleanup();
}
}

View File

@ -69,10 +69,10 @@ class ServerDebugger extends LocalDebugger {
super(databaseDescriptor);
}
private CommunicationInterface comm;
private Communication comm;
void setCommunicationInterface(CommunicationInterface communicationInterface) {
this.comm = communicationInterface;
void setCommunicationInterface(Communication communication) {
this.comm = communication;
}
private void setLoggingActive(boolean isActive) {