[#1249] Add breakpoint capability to jOOQ Console - Initial breakpoint
code structure.
This commit is contained in:
parent
d11e54a33e
commit
b97d23fd0f
92
jOOQ-console/src/main/java/org/jooq/debug/Breakpoint.java
Normal file
92
jOOQ-console/src/main/java/org/jooq/debug/Breakpoint.java
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class Breakpoint implements Serializable {
|
||||
|
||||
private int id;
|
||||
private StatementMatcher statementMatcher;
|
||||
// private Integer hitCount;
|
||||
private boolean isBreaking;
|
||||
private StatementProcessor beforeExecutionProcessor;
|
||||
private StatementProcessor replacementExecutionProcessor;
|
||||
private StatementProcessor afterExecutionProcessor;
|
||||
|
||||
public Breakpoint(int id, StatementMatcher statementMatcher, boolean isBreaking, StatementProcessor beforeExecutionProcessor, StatementProcessor replacementExecutionProcessor, StatementProcessor afterExecutionProcessor) {
|
||||
this.id = id;
|
||||
this.statementMatcher = statementMatcher;
|
||||
this.isBreaking = isBreaking;
|
||||
this.beforeExecutionProcessor = beforeExecutionProcessor;
|
||||
this.replacementExecutionProcessor = replacementExecutionProcessor;
|
||||
this.afterExecutionProcessor = afterExecutionProcessor;
|
||||
}
|
||||
|
||||
public int getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public StatementMatcher getStatementMatcher() {
|
||||
return statementMatcher;
|
||||
}
|
||||
|
||||
public boolean matches(StatementInfo statementInfo) {
|
||||
return statementMatcher != null && statementMatcher.matches(statementInfo);
|
||||
}
|
||||
|
||||
public boolean isBreaking() {
|
||||
return isBreaking;
|
||||
}
|
||||
|
||||
public StatementProcessor getBeforeExecutionProcessor() {
|
||||
return beforeExecutionProcessor;
|
||||
}
|
||||
|
||||
public StatementProcessor getReplacementExecutionProcessor() {
|
||||
return replacementExecutionProcessor;
|
||||
}
|
||||
|
||||
public StatementProcessor getAfterExecutionProcessor() {
|
||||
return afterExecutionProcessor;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class BreakpointAfterExecutionHit implements Serializable {
|
||||
|
||||
private int breakpointID;
|
||||
private String sql;
|
||||
|
||||
public BreakpointAfterExecutionHit(int breakpointID, String sql) {
|
||||
this.breakpointID = breakpointID;
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
public int getBreakpointID() {
|
||||
return breakpointID;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class BreakpointBeforeExecutionHit implements Serializable {
|
||||
|
||||
public static enum ExecutionType {
|
||||
STEP_THROUGH,
|
||||
RUN_OVER,
|
||||
RUN,
|
||||
}
|
||||
|
||||
private Integer breakpointID;
|
||||
private String sql;
|
||||
|
||||
public BreakpointBeforeExecutionHit(int breakpointID, String sql) {
|
||||
this.breakpointID = breakpointID;
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null if the breakpoint was processed and contains an execution type.
|
||||
*/
|
||||
public Integer getBreakpointID() {
|
||||
return breakpointID;
|
||||
}
|
||||
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
|
||||
private ExecutionType executionType = ExecutionType.RUN;
|
||||
|
||||
public void setExecutionType(ExecutionType executionType, String sql) {
|
||||
this.breakpointID = null;
|
||||
this.executionType = executionType;
|
||||
this.sql = sql;
|
||||
}
|
||||
|
||||
public ExecutionType getExecutionType() {
|
||||
return executionType;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public interface BreakpointHitHandler {
|
||||
|
||||
public void processBreakpointBeforeExecutionHit(BreakpointBeforeExecutionHit breakpointHit);
|
||||
|
||||
public void processBreakpointAfterExecutionHit(BreakpointAfterExecutionHit breakpointHit);
|
||||
|
||||
}
|
||||
@ -39,20 +39,26 @@ package org.jooq.debug;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jooq.ExecuteContext;
|
||||
import org.jooq.ExecuteType;
|
||||
import org.jooq.debug.BreakpointBeforeExecutionHit.ExecutionType;
|
||||
import org.jooq.impl.DefaultExecuteListener;
|
||||
import org.jooq.impl.Factory;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class DebugListener extends DefaultExecuteListener {
|
||||
|
||||
private boolean isLogging;
|
||||
private boolean hasDebuggers;
|
||||
|
||||
@Override
|
||||
public void renderStart(ExecuteContext ctx) {
|
||||
isLogging = !DebuggerRegistry.getDebuggerList().isEmpty();
|
||||
hasDebuggers = !DebuggerRegistry.getDebuggerList().isEmpty();
|
||||
startPreparationTime = 0;
|
||||
aggregatedPreparationDuration = 0;
|
||||
startBindTime = 0;
|
||||
@ -66,7 +72,7 @@ public class DebugListener extends DefaultExecuteListener {
|
||||
|
||||
@Override
|
||||
public void prepareStart(ExecuteContext ctx) {
|
||||
if(!isLogging) {
|
||||
if(!hasDebuggers) {
|
||||
return;
|
||||
}
|
||||
startPreparationTime = System.currentTimeMillis();
|
||||
@ -74,7 +80,7 @@ public class DebugListener extends DefaultExecuteListener {
|
||||
|
||||
@Override
|
||||
public void prepareEnd(ExecuteContext ctx) {
|
||||
if(!isLogging) {
|
||||
if(!hasDebuggers) {
|
||||
return;
|
||||
}
|
||||
aggregatedPreparationDuration += System.currentTimeMillis() - startPreparationTime;
|
||||
@ -91,7 +97,7 @@ public class DebugListener extends DefaultExecuteListener {
|
||||
|
||||
@Override
|
||||
public void bindStart(ExecuteContext ctx) {
|
||||
if(!isLogging) {
|
||||
if(!hasDebuggers) {
|
||||
return;
|
||||
}
|
||||
startBindTime = System.currentTimeMillis();
|
||||
@ -99,7 +105,7 @@ public class DebugListener extends DefaultExecuteListener {
|
||||
|
||||
@Override
|
||||
public void bindEnd(ExecuteContext ctx) {
|
||||
if(!isLogging) {
|
||||
if(!hasDebuggers) {
|
||||
return;
|
||||
}
|
||||
endBindTime = System.currentTimeMillis();
|
||||
@ -107,80 +113,241 @@ public class DebugListener extends DefaultExecuteListener {
|
||||
|
||||
private long startExecutionTime;
|
||||
private long endExecutionTime;
|
||||
private String matchingSQL;
|
||||
private String effectiveSQL;
|
||||
private Breakpoint matchingBreakpoint;
|
||||
private BreakpointHitHandler matchingBreakpointHitHandler;
|
||||
|
||||
@Override
|
||||
public void executeStart(ExecuteContext ctx) {
|
||||
if(!isLogging) {
|
||||
return;
|
||||
}
|
||||
BreakpointHitHandler breakpointHitHandler = null;
|
||||
List<Debugger> debuggerList = DebuggerRegistry.getDebuggerList();
|
||||
if(!debuggerList.isEmpty()) {
|
||||
StatementInfo statementInfo = null;
|
||||
bp: for(Debugger debugger: debuggerList) {
|
||||
Breakpoint[] breakpoints = debugger.getBreakpoints();
|
||||
if(breakpoints != null) {
|
||||
for(Breakpoint breakpoint: breakpoints) {
|
||||
if(statementInfo == null) {
|
||||
String[] sql = ctx.batchSQL();
|
||||
SqlQueryType sqlQueryType = SqlQueryType.detectType(sql[0]);
|
||||
String parameterDescription = null;
|
||||
if(sql.length == 1) {
|
||||
matchingSQL = sql[0];
|
||||
PreparedStatement statement = ctx.statement();
|
||||
if(statement instanceof UsageTrackingPreparedStatement) {
|
||||
parameterDescription = ((UsageTrackingPreparedStatement) statement).getParameterDescription();
|
||||
}
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(int i=0; i<sql.length; i++) {
|
||||
if(i > 0) {
|
||||
sb.append('\n');
|
||||
}
|
||||
sb.append(sql[i]);
|
||||
}
|
||||
matchingSQL = sb.toString();
|
||||
}
|
||||
statementInfo = new StatementInfo(sqlQueryType, sql, parameterDescription);
|
||||
}
|
||||
if(breakpoint.matches(statementInfo)) {
|
||||
matchingBreakpoint = breakpoint;
|
||||
if(breakpoint.isBreaking()) {
|
||||
breakpointHitHandler = debugger.getBreakpointHitHandler();
|
||||
}
|
||||
break bp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// We consider raw SQL (not the parameters). If we want to match on parameters, this should be a separate matcher.
|
||||
// For batched execution of in-lined statements, we aggregate the statements as a multiple-line one for matching purposes.
|
||||
if(matchingBreakpoint != null) {
|
||||
StatementProcessor beforeExecutionProcessor = matchingBreakpoint.getBeforeExecutionProcessor();
|
||||
if(beforeExecutionProcessor != null) {
|
||||
String sql = beforeExecutionProcessor.processSQL(matchingSQL);
|
||||
long subStartExecutionTime = System.currentTimeMillis();
|
||||
executeSQL(ctx, sql);
|
||||
long subEndExecutionTime = System.currentTimeMillis();
|
||||
// Log result of pre-processing.
|
||||
for(Debugger listener: debuggerList) {
|
||||
LoggingListener loggingListener = listener.getLoggingListener();
|
||||
if(loggingListener != null) {
|
||||
SqlQueryType sqlQueryType = SqlQueryType.detectType(sql);
|
||||
QueryLoggingData queryLoggingData = new QueryLoggingData(sqlQueryType, new String[] {sql}, null, null, null, subEndExecutionTime - subStartExecutionTime);
|
||||
StatementMatcher[] loggingStatementMatchers = listener.getLoggingStatementMatchers();
|
||||
if(loggingStatementMatchers == null) {
|
||||
loggingListener.logQueries(queryLoggingData);
|
||||
} else for(StatementMatcher statementMatcher: loggingStatementMatchers) {
|
||||
if(statementMatcher.matches(queryLoggingData)) {
|
||||
loggingListener.logQueries(queryLoggingData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
String mainSQL = null;
|
||||
StatementProcessor replacementExecutionProcessor = matchingBreakpoint.getReplacementExecutionProcessor();
|
||||
if(replacementExecutionProcessor != null) {
|
||||
mainSQL = replacementExecutionProcessor.processSQL(matchingSQL);
|
||||
try {
|
||||
ctx.statement().close();
|
||||
ctx.sql(mainSQL);
|
||||
ctx.statement(ctx.getConnection().prepareStatement(mainSQL));
|
||||
} catch(Exception e) {
|
||||
// TODO: how to process properly breakpoint errors??
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
ExecutionType executionType = BreakpointBeforeExecutionHit.ExecutionType.RUN;
|
||||
if(breakpointHitHandler != null) {
|
||||
effectiveSQL = mainSQL != null? mainSQL: matchingSQL;
|
||||
// TODO: find a way for the handler to replace the statement (not just step over).
|
||||
BreakpointBeforeExecutionHit breakpointBeforeExecutionHit = new BreakpointBeforeExecutionHit(matchingBreakpoint.getID(), effectiveSQL);
|
||||
breakpointHitHandler.processBreakpointBeforeExecutionHit(breakpointBeforeExecutionHit);
|
||||
executionType = breakpointBeforeExecutionHit.getExecutionType();
|
||||
}
|
||||
switch(executionType) {
|
||||
case STEP_THROUGH: {
|
||||
matchingBreakpointHitHandler = breakpointHitHandler;
|
||||
break;
|
||||
}
|
||||
case RUN_OVER: {
|
||||
try {
|
||||
ctx.statement().close();
|
||||
// Better return possibility? Based on originating query?
|
||||
String sql = new Factory(ctx.getDialect()).selectZero().where("1 = 2").getSQL();
|
||||
ctx.sql(sql);
|
||||
ctx.statement(ctx.getConnection().prepareStatement(sql));
|
||||
} catch(Exception e) {
|
||||
// TODO: how to process properly breakpoint errors??
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!hasDebuggers) {
|
||||
return;
|
||||
}
|
||||
startExecutionTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
private void executeSQL(ExecuteContext ctx, String sql) {
|
||||
Statement statement = null;
|
||||
try {
|
||||
statement = ctx.getConnection().createStatement();
|
||||
statement.execute(sql);
|
||||
} catch(Exception e) {
|
||||
// TODO: how to process properly breakpoint errors??
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
if(statement != null) {
|
||||
try {
|
||||
statement.close();
|
||||
} catch(Exception e) {
|
||||
// No error for closing problems.
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeEnd(ExecuteContext ctx) {
|
||||
if(!isLogging) {
|
||||
if(!hasDebuggers) {
|
||||
return;
|
||||
}
|
||||
endExecutionTime = System.currentTimeMillis();
|
||||
List<Debugger> debuggerList = DebuggerRegistry.getDebuggerList();
|
||||
if(debuggerList.isEmpty()) {
|
||||
return;
|
||||
if(matchingBreakpointHitHandler != null) {
|
||||
matchingBreakpointHitHandler.processBreakpointAfterExecutionHit(new BreakpointAfterExecutionHit(matchingBreakpoint.getID(), effectiveSQL));
|
||||
}
|
||||
boolean hasListener = false;
|
||||
for(Debugger listener: debuggerList) {
|
||||
LoggingListener loggingListener = listener.getLoggingListener();
|
||||
if(loggingListener != null) {
|
||||
hasListener = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!hasListener) {
|
||||
return;
|
||||
}
|
||||
ResultSet resultSet = ctx.resultSet();
|
||||
String[] sql = ctx.batchSQL();
|
||||
SqlQueryType sqlQueryType = SqlQueryType.detectType(sql[0]);
|
||||
String parameterDescription = null;
|
||||
if(sql.length == 1) {
|
||||
PreparedStatement statement = ctx.statement();
|
||||
if(statement instanceof UsageTrackingPreparedStatement) {
|
||||
parameterDescription = ((UsageTrackingPreparedStatement) statement).getParameterDescription();
|
||||
List<Debugger> debuggerList = DebuggerRegistry.getDebuggerList();
|
||||
if(!debuggerList.isEmpty()) {
|
||||
boolean hasListener = false;
|
||||
for(Debugger debugger: debuggerList) {
|
||||
LoggingListener loggingListener = debugger.getLoggingListener();
|
||||
if(loggingListener != null) {
|
||||
hasListener = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
QueryLoggingData queryLoggingData = new QueryLoggingData(sqlQueryType, sql, parameterDescription, startPreparationTime == 0? null: aggregatedPreparationDuration, startBindTime == 0? null: endBindTime - startBindTime, endExecutionTime - startExecutionTime);
|
||||
final List<LoggingListener> loggingListenerList = new ArrayList<LoggingListener>(debuggerList.size());
|
||||
for(Debugger listener: debuggerList) {
|
||||
LoggingListener loggingListener = listener.getLoggingListener();
|
||||
if(loggingListener != null) {
|
||||
StatementMatcher[] loggingStatementMatchers = listener.getLoggingStatementMatchers();
|
||||
if(loggingStatementMatchers == null) {
|
||||
loggingListenerList.add(loggingListener);
|
||||
loggingListener.logQueries(queryLoggingData);
|
||||
} else for(StatementMatcher statementMatcher: loggingStatementMatchers) {
|
||||
if(statementMatcher.matches(queryLoggingData)) {
|
||||
loggingListenerList.add(loggingListener);
|
||||
loggingListener.logQueries(queryLoggingData);
|
||||
break;
|
||||
if(hasListener) {
|
||||
String[] sql = ctx.batchSQL();
|
||||
SqlQueryType sqlQueryType = SqlQueryType.detectType(sql[0]);
|
||||
String parameterDescription = null;
|
||||
if(sql.length == 1) {
|
||||
PreparedStatement statement = ctx.statement();
|
||||
if(statement instanceof UsageTrackingPreparedStatement) {
|
||||
parameterDescription = ((UsageTrackingPreparedStatement) statement).getParameterDescription();
|
||||
}
|
||||
}
|
||||
QueryLoggingData queryLoggingData = new QueryLoggingData(sqlQueryType, sql, parameterDescription, startPreparationTime == 0? null: aggregatedPreparationDuration, startBindTime == 0? null: endBindTime - startBindTime, endExecutionTime - startExecutionTime);
|
||||
final List<LoggingListener> loggingListenerList = new ArrayList<LoggingListener>(debuggerList.size());
|
||||
for(Debugger listener: debuggerList) {
|
||||
LoggingListener loggingListener = listener.getLoggingListener();
|
||||
if(loggingListener != null) {
|
||||
StatementMatcher[] loggingStatementMatchers = listener.getLoggingStatementMatchers();
|
||||
if(loggingStatementMatchers == null) {
|
||||
loggingListenerList.add(loggingListener);
|
||||
loggingListener.logQueries(queryLoggingData);
|
||||
} else for(StatementMatcher statementMatcher: loggingStatementMatchers) {
|
||||
if(statementMatcher.matches(queryLoggingData)) {
|
||||
loggingListenerList.add(loggingListener);
|
||||
loggingListener.logQueries(queryLoggingData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ResultSet resultSet = ctx.resultSet();
|
||||
if(resultSet != null && !loggingListenerList.isEmpty()) {
|
||||
final int queryLoggingDataID = queryLoggingData.getID();
|
||||
ResultSet newResultSet = new UsageTrackingResultSet(resultSet) {
|
||||
@Override
|
||||
protected void notifyData(long lifeTime, int readRows, int readCount, int writeCount) {
|
||||
ResultSetLoggingData resultSetLoggingData = null;
|
||||
for(LoggingListener loggingListener: loggingListenerList) {
|
||||
if(resultSetLoggingData == null) {
|
||||
resultSetLoggingData = new ResultSetLoggingData(lifeTime, readRows, readCount, writeCount);
|
||||
}
|
||||
loggingListener.logResultSet(queryLoggingDataID, resultSetLoggingData);
|
||||
}
|
||||
}
|
||||
};
|
||||
ctx.resultSet(newResultSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(resultSet != null && !loggingListenerList.isEmpty()) {
|
||||
final int queryLoggingDataID = queryLoggingData.getID();
|
||||
ResultSet newResultSet = new UsageTrackingResultSet(resultSet) {
|
||||
@Override
|
||||
protected void notifyData(long lifeTime, int readRows, int readCount, int writeCount) {
|
||||
ResultSetLoggingData resultSetLoggingData = null;
|
||||
for(LoggingListener loggingListener: loggingListenerList) {
|
||||
if(resultSetLoggingData == null) {
|
||||
resultSetLoggingData = new ResultSetLoggingData(lifeTime, readRows, readCount, writeCount);
|
||||
}
|
||||
loggingListener.logResultSet(queryLoggingDataID, resultSetLoggingData);
|
||||
}
|
||||
}
|
||||
};
|
||||
ctx.resultSet(newResultSet);
|
||||
}
|
||||
if(matchingBreakpoint != null) {
|
||||
StatementProcessor afterExecutionProcessor = matchingBreakpoint.getAfterExecutionProcessor();
|
||||
matchingBreakpoint = null;
|
||||
if(afterExecutionProcessor != null) {
|
||||
String sql = afterExecutionProcessor.processSQL(matchingSQL);
|
||||
long subStartExecutionTime = System.currentTimeMillis();
|
||||
executeSQL(ctx, sql);
|
||||
long subEndExecutionTime = System.currentTimeMillis();
|
||||
// Log result of pre-processing.
|
||||
for(Debugger listener: debuggerList) {
|
||||
LoggingListener loggingListener = listener.getLoggingListener();
|
||||
if(loggingListener != null) {
|
||||
SqlQueryType sqlQueryType = SqlQueryType.detectType(sql);
|
||||
QueryLoggingData queryLoggingData = new QueryLoggingData(sqlQueryType, new String[] {sql}, null, null, null, subEndExecutionTime - subStartExecutionTime);
|
||||
StatementMatcher[] loggingStatementMatchers = listener.getLoggingStatementMatchers();
|
||||
if(loggingStatementMatchers == null) {
|
||||
loggingListener.logQueries(queryLoggingData);
|
||||
} else for(StatementMatcher statementMatcher: loggingStatementMatchers) {
|
||||
if(statementMatcher.matches(queryLoggingData)) {
|
||||
loggingListener.logQueries(queryLoggingData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// private long startFetchTime;
|
||||
|
||||
@ -37,7 +37,9 @@
|
||||
package org.jooq.debug;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public interface Debugger {
|
||||
|
||||
/**
|
||||
@ -51,6 +53,14 @@ public interface Debugger {
|
||||
|
||||
public StatementMatcher[] getLoggingStatementMatchers();
|
||||
|
||||
public void setBreakpoints(Breakpoint[] breakpoints);
|
||||
|
||||
public void setBreakpointHitHandler(BreakpointHitHandler breakpointHitHandler);
|
||||
|
||||
public BreakpointHitHandler getBreakpointHitHandler();
|
||||
|
||||
public Breakpoint[] getBreakpoints();
|
||||
|
||||
public boolean isExecutionSupported();
|
||||
|
||||
public StatementExecutor createStatementExecutor();
|
||||
|
||||
@ -39,6 +39,9 @@ package org.jooq.debug;
|
||||
import org.jooq.debug.console.DatabaseDescriptor;
|
||||
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class LocalDebugger implements Debugger {
|
||||
|
||||
private DatabaseDescriptor databaseDescriptor;
|
||||
@ -48,27 +51,74 @@ public class LocalDebugger implements Debugger {
|
||||
}
|
||||
|
||||
private LoggingListener loggingListener;
|
||||
private final Object LOGGING_LISTENER_LOCK = new Object();
|
||||
|
||||
@Override
|
||||
public void setLoggingListener(LoggingListener loggingListener) {
|
||||
this.loggingListener = loggingListener;
|
||||
synchronized (LOGGING_LISTENER_LOCK) {
|
||||
this.loggingListener = loggingListener;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoggingListener getLoggingListener() {
|
||||
return loggingListener;
|
||||
synchronized (LOGGING_LISTENER_LOCK) {
|
||||
return loggingListener;
|
||||
}
|
||||
}
|
||||
|
||||
private StatementMatcher[] loggingStatementMatchers;
|
||||
private final Object LOGGING_STATEMENT_MATCHERS_LOCK = new Object();
|
||||
|
||||
@Override
|
||||
public void setLoggingStatementMatchers(StatementMatcher[] loggingStatementMatchers) {
|
||||
this.loggingStatementMatchers = loggingStatementMatchers;
|
||||
synchronized (LOGGING_STATEMENT_MATCHERS_LOCK) {
|
||||
this.loggingStatementMatchers = loggingStatementMatchers;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementMatcher[] getLoggingStatementMatchers() {
|
||||
return loggingStatementMatchers;
|
||||
synchronized (LOGGING_STATEMENT_MATCHERS_LOCK) {
|
||||
return loggingStatementMatchers;
|
||||
}
|
||||
}
|
||||
|
||||
private Breakpoint[] breakpoints;
|
||||
private final Object BREAKPOINT_LOCK = new Object();
|
||||
|
||||
@Override
|
||||
public void setBreakpoints(Breakpoint[] breakpoints) {
|
||||
if(breakpoints != null && breakpoints.length == 0) {
|
||||
breakpoints = null;
|
||||
}
|
||||
synchronized (BREAKPOINT_LOCK) {
|
||||
this.breakpoints = breakpoints;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Breakpoint[] getBreakpoints() {
|
||||
synchronized (BREAKPOINT_LOCK) {
|
||||
return breakpoints;
|
||||
}
|
||||
}
|
||||
|
||||
private BreakpointHitHandler breakpointHitHandler;
|
||||
private final Object BREAKPOINT_HIT_HANDLER_LOCK = new Object();
|
||||
|
||||
@Override
|
||||
public void setBreakpointHitHandler(BreakpointHitHandler breakpointHitHandler) {
|
||||
synchronized (BREAKPOINT_HIT_HANDLER_LOCK) {
|
||||
this.breakpointHitHandler = breakpointHitHandler;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BreakpointHitHandler getBreakpointHitHandler() {
|
||||
synchronized (BREAKPOINT_HIT_HANDLER_LOCK) {
|
||||
return breakpointHitHandler;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -68,6 +68,9 @@ import org.jooq.debug.StatementExecutionResultSetResult.TypeInfo;
|
||||
import org.jooq.debug.console.DatabaseDescriptor;
|
||||
import org.jooq.debug.console.misc.Utils;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class LocalStatementExecutor implements StatementExecutor {
|
||||
|
||||
private DatabaseDescriptor databaseDescriptor;
|
||||
|
||||
@ -37,6 +37,9 @@
|
||||
package org.jooq.debug;
|
||||
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public interface LoggingListener {
|
||||
|
||||
public void logQueries(QueryLoggingData queryLoggingData);
|
||||
|
||||
@ -39,7 +39,6 @@ package org.jooq.debug;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
|
||||
@ -37,7 +37,9 @@
|
||||
package org.jooq.debug;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class StatementExecution {
|
||||
|
||||
private long executionDuration;
|
||||
|
||||
@ -39,6 +39,9 @@ package org.jooq.debug;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class StatementExecutionMessageResult implements StatementExecutionResult {
|
||||
|
||||
private String message;
|
||||
|
||||
@ -37,6 +37,9 @@
|
||||
package org.jooq.debug;
|
||||
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public interface StatementExecutionResult {
|
||||
|
||||
}
|
||||
|
||||
@ -42,6 +42,9 @@ import java.sql.SQLException;
|
||||
|
||||
import org.jooq.debug.console.misc.Utils;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class StatementExecutionResultSetResult implements StatementExecutionResult {
|
||||
|
||||
public static class TypeInfo {
|
||||
|
||||
@ -37,6 +37,9 @@
|
||||
package org.jooq.debug;
|
||||
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public interface StatementExecutor {
|
||||
|
||||
public StatementExecution execute(String sql, int maxRSRowsParsing, int retainParsedRSDataRowCountThreshold);
|
||||
|
||||
@ -38,6 +38,9 @@ package org.jooq.debug;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class StatementInfo implements Serializable {
|
||||
|
||||
|
||||
@ -42,6 +42,9 @@ import java.util.Set;
|
||||
|
||||
import org.jooq.debug.console.misc.TextMatcher;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class StatementMatcher implements Serializable {
|
||||
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.jooq.debug.console.misc.Utils;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class StatementProcessor implements Serializable {
|
||||
|
||||
public static enum ProcessorExecutionType {
|
||||
STATIC("Static SQL"),
|
||||
SED_LIKE_REG_EXP("Sed-like Reg. Exp."),
|
||||
;
|
||||
private String name;
|
||||
private ProcessorExecutionType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private ProcessorExecutionType type;
|
||||
private String text;
|
||||
|
||||
public StatementProcessor(ProcessorExecutionType type, String text) {
|
||||
this.type = type;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public ProcessorExecutionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public String processSQL(String sql) {
|
||||
switch(type) {
|
||||
case STATIC: return text;
|
||||
case SED_LIKE_REG_EXP: return Utils.applySedRegularExpression(sql, text);
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
}
|
||||
@ -58,6 +58,9 @@ import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
abstract class UsageTrackingResultSet implements ResultSet {
|
||||
|
||||
private ResultSet resultSet;
|
||||
|
||||
@ -0,0 +1,311 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JRadioButton;
|
||||
|
||||
import org.jooq.debug.Breakpoint;
|
||||
import org.jooq.debug.SqlQueryType;
|
||||
import org.jooq.debug.StatementMatcher;
|
||||
import org.jooq.debug.StatementProcessor;
|
||||
import org.jooq.debug.console.misc.TextMatcher;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class BreakpointEditor extends JPanel {
|
||||
|
||||
private static final String BREAK = "Break on match";
|
||||
private static final String PROCESS = "Process on match";
|
||||
|
||||
private int id;
|
||||
private JCheckBox threadNameTextMatcherCheckBox;
|
||||
private TextMatcherPane threadNameTextMatcherPane;
|
||||
private JCheckBox statementTextMatcherCheckBox;
|
||||
private TextMatcherPane statementTextMatcherPane;
|
||||
private JCheckBox statementTypeCheckBox;
|
||||
private JCheckBox statementTypeSelectCheckBox;
|
||||
private JCheckBox statementTypeUpdateCheckBox;
|
||||
private JCheckBox statementTypeInsertCheckBox;
|
||||
private JCheckBox statementTypeDeleteCheckBox;
|
||||
private JCheckBox statementTypeOtherCheckBox;
|
||||
private JComboBox breakpointTypeComboBox;
|
||||
private JPanel processorPane;
|
||||
private JCheckBox beforeExecutionCheckBox;
|
||||
private StatementProcessorPane beforeExecutionProcessorPane;
|
||||
private JRadioButton executeRadioButton;
|
||||
// private JRadioButton doNotExecuteRadioButton;
|
||||
private JRadioButton replaceExecutionRadioButton;
|
||||
private StatementProcessorPane replacementExecutionProcessorPane;
|
||||
private JCheckBox afterExecutionCheckBox;
|
||||
private StatementProcessorPane afterExecutionProcessorPane;
|
||||
|
||||
public BreakpointEditor(final DebuggerPane debuggerPane, Breakpoint breakpoint) {
|
||||
super(new GridBagLayout());
|
||||
StatementMatcher statementMatcher = breakpoint.getStatementMatcher();
|
||||
id = breakpoint.getID();
|
||||
if(statementMatcher == null) {
|
||||
statementMatcher = new StatementMatcher(null, null, null, true);
|
||||
}
|
||||
int y = 0;
|
||||
TextMatcher statementTextMatcher = statementMatcher.getStatementTextMatcher();
|
||||
statementTextMatcherCheckBox = new JCheckBox("Statement", statementTextMatcher != null);
|
||||
statementTextMatcherCheckBox.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
adjustStates();
|
||||
}
|
||||
});
|
||||
add(statementTextMatcherCheckBox, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
statementTextMatcherPane = new TextMatcherPane(statementTextMatcher);
|
||||
add(statementTextMatcherPane, new GridBagConstraints(1, y, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
|
||||
y++;
|
||||
Set<SqlQueryType> queryTypeSet = statementMatcher.getQueryTypeSet();
|
||||
statementTypeCheckBox = new JCheckBox("Type", queryTypeSet != null);
|
||||
statementTypeCheckBox.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
adjustStates();
|
||||
}
|
||||
});
|
||||
add(statementTypeCheckBox, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
JPanel typesPane = new JPanel(new GridBagLayout());
|
||||
statementTypeSelectCheckBox = new JCheckBox("SELECT", queryTypeSet != null && queryTypeSet.contains(SqlQueryType.SELECT));
|
||||
typesPane.add(statementTypeSelectCheckBox, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
statementTypeUpdateCheckBox = new JCheckBox("UPDATE", queryTypeSet != null && queryTypeSet.contains(SqlQueryType.UPDATE));
|
||||
typesPane.add(statementTypeUpdateCheckBox, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 2, 0, 0), 0, 0));
|
||||
statementTypeInsertCheckBox = new JCheckBox("INSERT", queryTypeSet != null && queryTypeSet.contains(SqlQueryType.INSERT));
|
||||
typesPane.add(statementTypeInsertCheckBox, new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 2, 0, 0), 0, 0));
|
||||
statementTypeDeleteCheckBox = new JCheckBox("DELETE", queryTypeSet != null && queryTypeSet.contains(SqlQueryType.DELETE));
|
||||
typesPane.add(statementTypeDeleteCheckBox, new GridBagConstraints(3, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 2, 0, 0), 0, 0));
|
||||
statementTypeOtherCheckBox = new JCheckBox("OTHER", queryTypeSet != null && queryTypeSet.contains(SqlQueryType.OTHER));
|
||||
typesPane.add(statementTypeOtherCheckBox, new GridBagConstraints(4, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 2, 0, 0), 0, 0));
|
||||
add(typesPane, new GridBagConstraints(1, y, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 0, 0), 0, 0));
|
||||
y++;
|
||||
TextMatcher threadNameTextMatcher = statementMatcher.getThreadNameTextMatcher();
|
||||
threadNameTextMatcherCheckBox = new JCheckBox("Thread name", threadNameTextMatcher != null);
|
||||
threadNameTextMatcherCheckBox.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
adjustStates();
|
||||
}
|
||||
});
|
||||
add(threadNameTextMatcherCheckBox, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
threadNameTextMatcherPane = new TextMatcherPane(threadNameTextMatcher);
|
||||
add(threadNameTextMatcherPane, new GridBagConstraints(1, y, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 0, 0), 0, 0));
|
||||
y++;
|
||||
breakpointTypeComboBox = new JComboBox(new Object[] {BREAK, PROCESS});
|
||||
breakpointTypeComboBox.setSelectedItem(breakpoint.isBreaking()? BREAK: PROCESS);
|
||||
breakpointTypeComboBox.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
adjustStates();
|
||||
}
|
||||
});
|
||||
add(breakpointTypeComboBox, new GridBagConstraints(0, y, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
y++;
|
||||
processorPane = new JPanel(new GridBagLayout());
|
||||
populateProcessorPane(breakpoint);
|
||||
add(processorPane, new GridBagConstraints(0, y, 2, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 20, 0, 0), 0, 0));
|
||||
y++;
|
||||
JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
|
||||
buttonPane.setBorder(BorderFactory.createEmptyBorder(20, 5, 5, 5));
|
||||
JButton applyButton = new JButton("Apply changes");
|
||||
applyButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
debuggerPane.modifyBreakpoint(getBreakpoint());
|
||||
}
|
||||
});
|
||||
buttonPane.add(applyButton);
|
||||
add(buttonPane, new GridBagConstraints(0, y, 2, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 20, 0, 0), 0, 0));
|
||||
add(Box.createGlue(), new GridBagConstraints(0, Short.MAX_VALUE, 1, 1, 0, 1, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
adjustStates();
|
||||
}
|
||||
|
||||
private void populateProcessorPane(Breakpoint breakpoint) {
|
||||
int y = 0;
|
||||
StatementProcessor beforeExecutionProcessor = breakpoint.getBeforeExecutionProcessor();
|
||||
beforeExecutionCheckBox = new JCheckBox("Execute before: ");
|
||||
beforeExecutionCheckBox.setSelected(beforeExecutionProcessor != null);
|
||||
beforeExecutionCheckBox.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
adjustStates();
|
||||
}
|
||||
});
|
||||
processorPane.add(beforeExecutionCheckBox, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
beforeExecutionProcessorPane = new StatementProcessorPane(beforeExecutionProcessor);
|
||||
processorPane.add(beforeExecutionProcessorPane, new GridBagConstraints(1, y, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
|
||||
y++;
|
||||
ButtonGroup executionButtonGroup = new ButtonGroup();
|
||||
StatementProcessor replacementExecutionProcessor = breakpoint.getReplacementExecutionProcessor();
|
||||
executeRadioButton = new JRadioButton("Execute");
|
||||
executionButtonGroup.add(executeRadioButton);
|
||||
processorPane.add(executeRadioButton, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
y++;
|
||||
// doNotExecuteRadioButton = new JRadioButton("Do not execute");
|
||||
// executionButtonGroup.add(doNotExecuteRadioButton);
|
||||
// processorPane.add(doNotExecuteRadioButton, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
// y++;
|
||||
replaceExecutionRadioButton = new JRadioButton("Replace with: ");
|
||||
executionButtonGroup.add(replaceExecutionRadioButton);
|
||||
if(replacementExecutionProcessor != null) {
|
||||
replaceExecutionRadioButton.setSelected(true);
|
||||
} else {
|
||||
executeRadioButton.setSelected(true);
|
||||
}
|
||||
processorPane.add(replaceExecutionRadioButton, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
replacementExecutionProcessorPane = new StatementProcessorPane(breakpoint.getReplacementExecutionProcessor());
|
||||
processorPane.add(replacementExecutionProcessorPane, new GridBagConstraints(1, y, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
|
||||
executeRadioButton.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
adjustStates();
|
||||
}
|
||||
});
|
||||
replaceExecutionRadioButton.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
adjustStates();
|
||||
}
|
||||
});
|
||||
y++;
|
||||
StatementProcessor afterExecutionProcessor = breakpoint.getAfterExecutionProcessor();
|
||||
afterExecutionCheckBox = new JCheckBox("Execute after: ");
|
||||
afterExecutionCheckBox.setSelected(afterExecutionProcessor != null);
|
||||
afterExecutionCheckBox.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
adjustStates();
|
||||
}
|
||||
});
|
||||
processorPane.add(afterExecutionCheckBox, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
afterExecutionProcessorPane = new StatementProcessorPane(afterExecutionProcessor);
|
||||
processorPane.add(afterExecutionProcessorPane, new GridBagConstraints(1, y, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
|
||||
}
|
||||
|
||||
private void adjustStates() {
|
||||
boolean isActive = true;
|
||||
statementTextMatcherCheckBox.setEnabled(isActive);
|
||||
statementTypeCheckBox.setEnabled(isActive);
|
||||
threadNameTextMatcherCheckBox.setEnabled(isActive);
|
||||
statementTextMatcherPane.setLocked(!isActive || !statementTextMatcherCheckBox.isSelected());
|
||||
statementTypeSelectCheckBox.setEnabled(isActive && statementTypeCheckBox.isSelected());
|
||||
statementTypeUpdateCheckBox.setEnabled(isActive && statementTypeCheckBox.isSelected());
|
||||
statementTypeInsertCheckBox.setEnabled(isActive && statementTypeCheckBox.isSelected());
|
||||
statementTypeDeleteCheckBox.setEnabled(isActive && statementTypeCheckBox.isSelected());
|
||||
statementTypeOtherCheckBox.setEnabled(isActive && statementTypeCheckBox.isSelected());
|
||||
threadNameTextMatcherPane.setLocked(!isActive || !threadNameTextMatcherCheckBox.isSelected());
|
||||
breakpointTypeComboBox.setEnabled(isActive && (statementTextMatcherCheckBox.isSelected() || statementTypeCheckBox.isSelected() || threadNameTextMatcherCheckBox.isSelected()));
|
||||
processorPane.setVisible(isActive && breakpointTypeComboBox.getSelectedItem() == PROCESS);
|
||||
beforeExecutionCheckBox.setEnabled(isActive);
|
||||
beforeExecutionProcessorPane.setLocked(!isActive || !beforeExecutionCheckBox.isSelected());
|
||||
executeRadioButton.setEnabled(isActive);
|
||||
replaceExecutionRadioButton.setEnabled(isActive);
|
||||
// doNotExecuteRadioButton;
|
||||
replacementExecutionProcessorPane.setLocked(!isActive || !replaceExecutionRadioButton.isSelected());
|
||||
afterExecutionCheckBox.setEnabled(isActive);
|
||||
afterExecutionProcessorPane.setLocked(!isActive || !afterExecutionCheckBox.isSelected());
|
||||
}
|
||||
|
||||
public StatementMatcher getStatementMatcher() {
|
||||
boolean isActive = true;//activeCheckBox.isSelected();
|
||||
TextMatcher threadNameTextMatcher = threadNameTextMatcherCheckBox.isSelected()? threadNameTextMatcherPane.getTextMatcher(): null;
|
||||
TextMatcher statementTextMatcher = statementTextMatcherCheckBox.isSelected()? statementTextMatcherPane.getTextMatcher(): null;
|
||||
Set<SqlQueryType> queryTypeSet;
|
||||
if(statementTypeCheckBox.isSelected()) {
|
||||
List<SqlQueryType> typeList = new ArrayList<SqlQueryType>();
|
||||
if(statementTypeSelectCheckBox.isSelected()) {
|
||||
typeList.add(SqlQueryType.SELECT);
|
||||
}
|
||||
if(statementTypeUpdateCheckBox.isSelected()) {
|
||||
typeList.add(SqlQueryType.UPDATE);
|
||||
}
|
||||
if(statementTypeInsertCheckBox.isSelected()) {
|
||||
typeList.add(SqlQueryType.INSERT);
|
||||
}
|
||||
if(statementTypeDeleteCheckBox.isSelected()) {
|
||||
typeList.add(SqlQueryType.DELETE);
|
||||
}
|
||||
if(statementTypeOtherCheckBox.isSelected()) {
|
||||
typeList.add(SqlQueryType.OTHER);
|
||||
}
|
||||
queryTypeSet = EnumSet.copyOf(typeList);
|
||||
} else {
|
||||
queryTypeSet = null;
|
||||
}
|
||||
return new StatementMatcher(threadNameTextMatcher, statementTextMatcher, queryTypeSet, isActive);
|
||||
}
|
||||
|
||||
public Breakpoint getBreakpoint() {
|
||||
StatementMatcher statementMatcher = getStatementMatcher();
|
||||
// Integer hitCount;
|
||||
boolean isBreaking = breakpointTypeComboBox.getSelectedItem() == BREAK;
|
||||
StatementProcessor beforeExecutionProcessor = null;
|
||||
StatementProcessor replacementExecutionProcessor = null;
|
||||
StatementProcessor afterExecutionProcessor = null;
|
||||
if(!isBreaking) {
|
||||
beforeExecutionProcessor = beforeExecutionCheckBox.isSelected()? beforeExecutionProcessorPane.getStatementProcessor(): null;
|
||||
replacementExecutionProcessor = replaceExecutionRadioButton.isSelected()? replacementExecutionProcessorPane.getStatementProcessor(): null;
|
||||
afterExecutionProcessor = afterExecutionCheckBox.isSelected()? afterExecutionProcessorPane.getStatementProcessor(): null;
|
||||
}
|
||||
return new Breakpoint(id, statementMatcher, isBreaking, beforeExecutionProcessor, replacementExecutionProcessor, afterExecutionProcessor);
|
||||
}
|
||||
|
||||
}
|
||||
@ -103,7 +103,7 @@ public class Console extends JFrame {
|
||||
private JTabbedPane mainTabbedPane;
|
||||
private JTabbedPane editorTabbedPane;
|
||||
|
||||
public Console(DatabaseDescriptor editorDatabaseDescriptor, boolean isShowingLoggingTab) {
|
||||
public Console(DatabaseDescriptor editorDatabaseDescriptor, boolean isShowingLoggingTab, boolean isShowingDebugger) {
|
||||
debugger = new LocalDebugger(editorDatabaseDescriptor);
|
||||
// Local debugger registration is managed by the console since it hides the debugger.
|
||||
addWindowListener(new WindowAdapter() {
|
||||
@ -116,20 +116,16 @@ public class Console extends JFrame {
|
||||
DebuggerRegistry.removeSqlQueryDebugger(debugger);
|
||||
}
|
||||
});
|
||||
init(isShowingLoggingTab);
|
||||
init(isShowingLoggingTab, isShowingDebugger);
|
||||
}
|
||||
|
||||
public Console(final Debugger debugger, boolean isShowingLoggingTab) {
|
||||
public Console(final Debugger debugger, boolean isShowingLoggingTab, boolean isShowingDebugger) {
|
||||
this.debugger = debugger;
|
||||
// Local debugger registration is handled externally if needed (e.g.: remote client must not be registered).
|
||||
init(isShowingLoggingTab);
|
||||
init(isShowingLoggingTab, isShowingDebugger);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param debugger
|
||||
* @param isShowingLoggingTab
|
||||
*/
|
||||
private void init(boolean isShowingLoggingTab) {
|
||||
private void init(boolean isShowingLoggingTab, boolean isShowingDebugger) {
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
JMenu fileMenu = new JMenu("File");
|
||||
@ -233,6 +229,9 @@ public class Console extends JFrame {
|
||||
if(isShowingLoggingTab) {
|
||||
addLoggerTab();
|
||||
}
|
||||
if(isShowingDebugger) {
|
||||
addDebuggerTab();
|
||||
}
|
||||
getContentPane().add(mainTabbedPane, BorderLayout.CENTER);
|
||||
setLocationByPlatform(true);
|
||||
setSize(800, 600);
|
||||
@ -263,6 +262,14 @@ public class Console extends JFrame {
|
||||
}
|
||||
}
|
||||
|
||||
private DebuggerPane sqlDebuggerPane;
|
||||
|
||||
private void addDebuggerTab() {
|
||||
sqlDebuggerPane = new DebuggerPane(debugger);
|
||||
mainTabbedPane.addTab("Debugger", sqlDebuggerPane);
|
||||
|
||||
}
|
||||
|
||||
private LoggerPane sqlLoggerPane;
|
||||
|
||||
private void addLoggerTab() {
|
||||
@ -407,7 +414,7 @@ public class Console extends JFrame {
|
||||
}
|
||||
|
||||
public static void openConsole(DatabaseDescriptor databaseDescriptor, boolean isLoggingActive) {
|
||||
Console sqlConsoleFrame = new Console(databaseDescriptor, true);
|
||||
Console sqlConsoleFrame = new Console(databaseDescriptor, true, true);
|
||||
sqlConsoleFrame.setLoggingActive(isLoggingActive);
|
||||
sqlConsoleFrame.setVisible(true);
|
||||
}
|
||||
@ -506,7 +513,7 @@ public class Console extends JFrame {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Console sqlConsoleFrame = new Console(debugger, true);
|
||||
Console sqlConsoleFrame = new Console(debugger, true, true);
|
||||
sqlConsoleFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
sqlConsoleFrame.setVisible(true);
|
||||
}
|
||||
|
||||
@ -0,0 +1,240 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.event.TreeSelectionEvent;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import org.jooq.debug.Breakpoint;
|
||||
import org.jooq.debug.Debugger;
|
||||
import org.jooq.debug.console.misc.CheckBoxNode;
|
||||
import org.jooq.debug.console.misc.CheckBoxNodeEditor;
|
||||
import org.jooq.debug.console.misc.CheckBoxNodeRenderer;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class DebuggerPane extends JPanel {
|
||||
|
||||
private Debugger debugger;
|
||||
private DefaultMutableTreeNode rootNode;
|
||||
private JTree breakpointTree;
|
||||
private DefaultTreeModel breakpointTreeModel;
|
||||
private JPanel eastPane;
|
||||
|
||||
public DebuggerPane(Debugger debugger) {
|
||||
super(new BorderLayout());
|
||||
this.debugger = debugger;
|
||||
JPanel westPane = new JPanel(new BorderLayout());
|
||||
JPanel breakpointAddPane = new JPanel(new GridBagLayout());
|
||||
final JTextField addBreakpointTextField = new JTextField(7);
|
||||
breakpointAddPane.add(addBreakpointTextField, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
|
||||
final JButton addBreakpointButton = new JButton("Add");
|
||||
addBreakpointButton.setEnabled(false);
|
||||
breakpointAddPane.add(addBreakpointButton, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 2, 0, 0), 0, 0));
|
||||
addBreakpointTextField.getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
adjustStates();
|
||||
}
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
adjustStates();
|
||||
}
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
adjustStates();
|
||||
}
|
||||
private void adjustStates() {
|
||||
// TODO: restrict to unique names?
|
||||
boolean isEnabled = addBreakpointTextField.getText().length() > 0;
|
||||
addBreakpointButton.setEnabled(isEnabled);
|
||||
}
|
||||
});
|
||||
ActionListener addBreakpointActionListener = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String name = addBreakpointTextField.getText();
|
||||
addBreakpointTextField.setText("");
|
||||
addBreakpoint(name);
|
||||
}
|
||||
};
|
||||
addBreakpointTextField.addActionListener(addBreakpointActionListener);
|
||||
addBreakpointButton.addActionListener(addBreakpointActionListener);
|
||||
westPane.add(breakpointAddPane, BorderLayout.NORTH);
|
||||
rootNode = new DefaultMutableTreeNode();
|
||||
breakpointTreeModel = new DefaultTreeModel(rootNode) {
|
||||
@Override
|
||||
public void valueForPathChanged(TreePath path, Object newValue) {
|
||||
if(newValue instanceof CheckBoxNode) {
|
||||
CheckBoxNode node = (CheckBoxNode)path.getLastPathComponent();
|
||||
node.setSelected(((CheckBoxNode) newValue).isSelected());
|
||||
super.valueForPathChanged(path, node.getUserObject());
|
||||
}
|
||||
}
|
||||
};
|
||||
breakpointTree = new JTree(breakpointTreeModel);
|
||||
breakpointTree.setRootVisible(false);
|
||||
breakpointTree.setCellRenderer(new CheckBoxNodeRenderer());
|
||||
breakpointTree.setCellEditor(new CheckBoxNodeEditor(breakpointTree));
|
||||
breakpointTree.setEditable(true);
|
||||
westPane.add(new JScrollPane(breakpointTree), BorderLayout.CENTER);
|
||||
JPanel breakpointRemovePane = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
|
||||
final JButton removeBreakpointButton = new JButton("Remove");
|
||||
removeBreakpointButton.setEnabled(false);
|
||||
removeBreakpointButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
TreePath[] paths = breakpointTree.getSelectionPaths();
|
||||
boolean isValid = paths != null && paths.length > 0;
|
||||
if(isValid) {
|
||||
for(int i=0; i<paths.length; i++) {
|
||||
if(!(paths[i].getLastPathComponent() instanceof CheckBoxNode)) {
|
||||
isValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isValid) {
|
||||
breakpointTree.cancelEditing();
|
||||
for(int i=0; i<paths.length; i++) {
|
||||
CheckBoxNode childNode = (CheckBoxNode)paths[i].getLastPathComponent();
|
||||
int index = rootNode.getIndex(childNode);
|
||||
rootNode.remove(index);
|
||||
breakpointTreeModel.nodesWereRemoved(rootNode, new int[] {index}, new Object[] {childNode});
|
||||
}
|
||||
commitBreakpoints();
|
||||
}
|
||||
}
|
||||
});
|
||||
breakpointTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(TreeSelectionEvent e) {
|
||||
TreePath[] paths = breakpointTree.getSelectionPaths();
|
||||
boolean isValid = paths != null && paths.length > 0;
|
||||
if(isValid) {
|
||||
for(int i=0; i<paths.length; i++) {
|
||||
if(!(paths[i].getLastPathComponent() instanceof CheckBoxNode)) {
|
||||
isValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
removeBreakpointButton.setEnabled(isValid);
|
||||
processTreeSelection();
|
||||
}
|
||||
});
|
||||
breakpointRemovePane.add(removeBreakpointButton);
|
||||
westPane.add(breakpointRemovePane, BorderLayout.SOUTH);
|
||||
eastPane = new JPanel(new BorderLayout());
|
||||
add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, westPane, eastPane), BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
private static int nextID = 1;
|
||||
|
||||
private void addBreakpoint(String name) {
|
||||
breakpointTree.cancelEditing();
|
||||
Breakpoint breakpoint = new Breakpoint(nextID++, null, true, null, null, null);
|
||||
CheckBoxNode breakpointNode = new CheckBoxNode(breakpoint, name, true);
|
||||
rootNode.add(breakpointNode);
|
||||
breakpointTreeModel.nodesWereInserted(rootNode, new int[] {rootNode.getIndex(breakpointNode)});
|
||||
breakpointTree.expandPath(new TreePath(rootNode));
|
||||
commitBreakpoints();
|
||||
}
|
||||
|
||||
void modifyBreakpoint(Breakpoint breakpoint) {
|
||||
int childCount = rootNode.getChildCount();
|
||||
for(int i=0; i<childCount; i++) {
|
||||
CheckBoxNode checkBoxNode = (CheckBoxNode)rootNode.getChildAt(i);
|
||||
Breakpoint breakpoint_ = (Breakpoint)checkBoxNode.getUserObject();
|
||||
if(breakpoint_.getID() == breakpoint.getID()) {
|
||||
checkBoxNode.setUserObject(breakpoint);
|
||||
commitBreakpoints();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void commitBreakpoints() {
|
||||
List<Breakpoint> breakpointList = new ArrayList<Breakpoint>();
|
||||
int childCount = rootNode.getChildCount();
|
||||
for(int i=0; i<childCount; i++) {
|
||||
CheckBoxNode node = (CheckBoxNode)rootNode.getChildAt(i);
|
||||
if(node.isSelected()) {
|
||||
breakpointList.add((Breakpoint)node.getUserObject());
|
||||
}
|
||||
}
|
||||
debugger.setBreakpoints(breakpointList.toArray(new Breakpoint[0]));
|
||||
}
|
||||
|
||||
private void processTreeSelection() {
|
||||
TreePath[] paths = breakpointTree.getSelectionPaths();
|
||||
// TODO: commit last value.
|
||||
eastPane.removeAll();
|
||||
if(paths != null && paths.length == 1) {
|
||||
Object o = ((DefaultMutableTreeNode)paths[0].getLastPathComponent()).getUserObject();
|
||||
if(o instanceof Breakpoint) {
|
||||
eastPane.add(new BreakpointEditor(this, (Breakpoint)o));
|
||||
}
|
||||
}
|
||||
eastPane.revalidate();
|
||||
eastPane.repaint();
|
||||
}
|
||||
|
||||
}
|
||||
@ -59,6 +59,9 @@ import org.jooq.debug.SqlQueryType;
|
||||
import org.jooq.debug.StatementMatcher;
|
||||
import org.jooq.debug.console.misc.TextMatcher;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class StatementMatcherPane extends JPanel {
|
||||
|
||||
@ -114,7 +117,7 @@ public class StatementMatcherPane extends JPanel {
|
||||
});
|
||||
add(statementTextMatcherCheckBox, new GridBagConstraints(0, y, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
statementTextMatcherPane = new TextMatcherPane(statementTextMatcher);
|
||||
add(statementTextMatcherPane, new GridBagConstraints(1, y, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 5, 0, 0), 0, 0));
|
||||
add(statementTextMatcherPane, new GridBagConstraints(1, y, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
|
||||
y++;
|
||||
Set<SqlQueryType> queryTypeSet = statementMatcher.getQueryTypeSet();
|
||||
statementTypeCheckBox = new JCheckBox("Type", queryTypeSet != null);
|
||||
|
||||
@ -53,6 +53,9 @@ import javax.swing.SwingUtilities;
|
||||
import org.jooq.debug.Debugger;
|
||||
import org.jooq.debug.StatementMatcher;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class StatementMatchersDialogBox extends JDialog {
|
||||
|
||||
|
||||
@ -51,6 +51,9 @@ import javax.swing.Scrollable;
|
||||
|
||||
import org.jooq.debug.StatementMatcher;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class StatementMatchersPane extends JPanel {
|
||||
|
||||
|
||||
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import org.jooq.debug.StatementProcessor;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class StatementProcessorPane extends JPanel {
|
||||
|
||||
private JComboBox processorTypeComboBox;
|
||||
private JTextField processorTextField;
|
||||
|
||||
public StatementProcessorPane(StatementProcessor statementProcessor) {
|
||||
super(new GridBagLayout());
|
||||
if(statementProcessor == null) {
|
||||
statementProcessor = new StatementProcessor(StatementProcessor.ProcessorExecutionType.STATIC, "");
|
||||
}
|
||||
processorTypeComboBox = new JComboBox(StatementProcessor.ProcessorExecutionType.values());
|
||||
processorTypeComboBox.setSelectedItem(statementProcessor.getType());
|
||||
add(processorTypeComboBox, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
|
||||
processorTextField = new JTextField(statementProcessor.getText(), 14);
|
||||
add(processorTextField, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
|
||||
}
|
||||
|
||||
public StatementProcessor getStatementProcessor() {
|
||||
return new StatementProcessor((StatementProcessor.ProcessorExecutionType)processorTypeComboBox.getSelectedItem(), processorTextField.getText());
|
||||
}
|
||||
|
||||
public void setLocked(boolean isLocked) {
|
||||
processorTypeComboBox.setEnabled(!isLocked);
|
||||
processorTextField.setEnabled(!isLocked);
|
||||
}
|
||||
|
||||
}
|
||||
@ -49,6 +49,9 @@ import org.jooq.debug.console.misc.TextMatcher;
|
||||
import org.jooq.debug.console.misc.TextMatcher.TextMatchingType;
|
||||
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class TextMatcherPane extends JPanel {
|
||||
|
||||
@ -61,7 +64,7 @@ public class TextMatcherPane extends JPanel {
|
||||
matcherTypeComboBox = new JComboBox(TextMatchingType.values());
|
||||
add(matcherTypeComboBox, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
textField = new JTextField(14);
|
||||
add(textField, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 2, 0, 0), 0, 0));
|
||||
add(textField, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 2, 0, 0), 0, 0));
|
||||
caseSensitiveCheckBox = new JCheckBox("Case sensitive");
|
||||
add(caseSensitiveCheckBox, new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 2, 0, 0), 0, 0));
|
||||
if(textMatcher != null) {
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
package org.jooq.debug.console.misc;
|
||||
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class CheckBoxNode extends DefaultMutableTreeNode {
|
||||
|
||||
private String text;
|
||||
private boolean selected;
|
||||
|
||||
public CheckBoxNode(Object o, String text, boolean selected) {
|
||||
super(o);
|
||||
this.text = text;
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
public void setSelected(boolean newValue) {
|
||||
selected = newValue;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package org.jooq.debug.console.misc;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.EventObject;
|
||||
|
||||
import javax.swing.AbstractCellEditor;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.tree.TreeCellEditor;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {
|
||||
|
||||
private CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
|
||||
private JTree tree;
|
||||
|
||||
public CheckBoxNodeEditor(JTree tree) {
|
||||
this.tree = tree;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCellEditorValue() {
|
||||
JCheckBox checkbox = renderer.getCheckBoxRenderer();
|
||||
return new CheckBoxNode(null, checkbox.getText(), checkbox.isSelected());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(EventObject event) {
|
||||
boolean returnValue = false;
|
||||
if (event instanceof MouseEvent) {
|
||||
MouseEvent mouseEvent = (MouseEvent) event;
|
||||
TreePath path = tree.getPathForLocation(mouseEvent.getX(), mouseEvent.getY());
|
||||
if (path != null) {
|
||||
Object node = path.getLastPathComponent();
|
||||
returnValue = node instanceof CheckBoxNode;
|
||||
}
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) {
|
||||
Component editor = renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true);
|
||||
// editor always selected / focused
|
||||
if (editor instanceof JCheckBox) {
|
||||
((JCheckBox) editor).addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent itemEvent) {
|
||||
if (stopCellEditing()) {
|
||||
fireEditingStopped();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
package org.jooq.debug.console.misc;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Font;
|
||||
import java.awt.Insets;
|
||||
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import javax.swing.tree.TreeCellRenderer;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class CheckBoxNodeRenderer implements TreeCellRenderer {
|
||||
|
||||
private JCheckBox checkBoxRenderer;
|
||||
|
||||
private DefaultTreeCellRenderer nonCheckBoxRenderer = new DefaultTreeCellRenderer();
|
||||
|
||||
Color selectionBorderColor, selectionForeground, selectionBackground, textForeground, textBackground;
|
||||
|
||||
protected JCheckBox getCheckBoxRenderer() {
|
||||
return checkBoxRenderer;
|
||||
}
|
||||
|
||||
public CheckBoxNodeRenderer() {
|
||||
checkBoxRenderer = new JCheckBox();
|
||||
checkBoxRenderer.setMargin(new Insets(0, 0, 0, 0));
|
||||
Font fontValue = UIManager.getFont("Tree.font");
|
||||
if (fontValue != null) {
|
||||
checkBoxRenderer.setFont(fontValue);
|
||||
}
|
||||
Boolean booleanValue = (Boolean) UIManager.get("Tree.drawsFocusBorderAroundIcon");
|
||||
checkBoxRenderer.setFocusPainted((booleanValue != null) && (booleanValue.booleanValue()));
|
||||
selectionBorderColor = UIManager.getColor("Tree.selectionBorderColor");
|
||||
selectionForeground = UIManager.getColor("Tree.selectionForeground");
|
||||
selectionBackground = UIManager.getColor("Tree.selectionBackground");
|
||||
textForeground = UIManager.getColor("Tree.textForeground");
|
||||
textBackground = UIManager.getColor("Tree.textBackground");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
|
||||
Object usedValue = value;// stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, false);
|
||||
if (value instanceof CheckBoxNode) {
|
||||
usedValue = ((CheckBoxNode) value).getText();
|
||||
}
|
||||
Component c = nonCheckBoxRenderer.getTreeCellRendererComponent(tree, usedValue, selected, expanded, leaf, row, hasFocus);
|
||||
if (value instanceof CheckBoxNode) {
|
||||
// checkBoxRenderer.setText(stringValue);
|
||||
checkBoxRenderer.setSelected(false);
|
||||
checkBoxRenderer.setEnabled(tree.isEnabled());
|
||||
checkBoxRenderer.setOpaque(false);
|
||||
// if (selected) {
|
||||
// checkBoxRenderer.setForeground(selectionForeground);
|
||||
// checkBoxRenderer.setBackground(selectionBackground);
|
||||
// } else {
|
||||
// checkBoxRenderer.setForeground(textForeground);
|
||||
// checkBoxRenderer.setBackground(textBackground);
|
||||
// }
|
||||
CheckBoxNode node = (CheckBoxNode) value;
|
||||
// checkBoxRenderer.setText(node.getText());
|
||||
checkBoxRenderer.setSelected(node.isSelected());
|
||||
JPanel pane = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
||||
pane.setOpaque(false);
|
||||
pane.add(checkBoxRenderer);
|
||||
pane.add(c);
|
||||
c = pane;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* 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.misc;
|
||||
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Insets;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class JSedRegExBuilder extends JPanel {
|
||||
|
||||
public JSedRegExBuilder(String patternSummary, String sampleText) {
|
||||
setLayout(new GridBagLayout());
|
||||
JPanel summaryPanel = new JPanel(new GridBagLayout());
|
||||
summaryPanel.add(new JLabel("Pattern summary: "), new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
|
||||
final JTextField summaryTextField = new JTextField(7);
|
||||
final JTextArea sampleTextTextArea = new JTextArea(sampleText);
|
||||
final JTextArea outputTextArea = new JTextArea();
|
||||
outputTextArea.setEditable(false);
|
||||
DocumentListener documentListener = new DocumentListener() {
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
update();
|
||||
}
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
update();
|
||||
}
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
update();
|
||||
}
|
||||
private void update() {
|
||||
try {
|
||||
outputTextArea.setText(Utils.applySedRegularExpression(sampleTextTextArea.getText(), summaryTextField.getText()));
|
||||
} catch(Exception e) {
|
||||
outputTextArea.setText(e.getMessage());
|
||||
outputTextArea.setCaretPosition(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
summaryTextField.getDocument().addDocumentListener(documentListener);
|
||||
summaryPanel.add(summaryTextField, new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
|
||||
add(summaryPanel, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
|
||||
add(new JLabel("Sample text:"), new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0));
|
||||
add(new JScrollPane(sampleTextTextArea), new GridBagConstraints(0, 2, 1, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
|
||||
add(new JLabel("Output:"), new GridBagConstraints(0, 3, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 0, 0));
|
||||
add(new JScrollPane(outputTextArea), new GridBagConstraints(0, 4, 1, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
|
||||
summaryTextField.setText(patternSummary);
|
||||
sampleTextTextArea.getDocument().addDocumentListener(documentListener);
|
||||
}
|
||||
|
||||
}
|
||||
@ -39,6 +39,9 @@ package org.jooq.debug.console.misc;
|
||||
import java.io.Serializable;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class TextMatcher implements Serializable {
|
||||
|
||||
|
||||
@ -43,6 +43,8 @@ import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers & others
|
||||
@ -287,4 +289,116 @@ public class Utils {
|
||||
return keywordSet.contains(s.substring(0, index));
|
||||
}
|
||||
|
||||
/**
|
||||
* A "sed -e" like reg exp, of the form:<br/>
|
||||
* - /regexp/flags: find and output the matches.<br/>
|
||||
* - /regexp/replacement/flags: replace the matches and output the resulting string.<br/>
|
||||
* Flags can be left empty or any combinations of the characters 'gidmsux' (g perfoms a replace all instead of just the first match. For other flags, refer to the Javadoc of Pattern).
|
||||
* It is also possible to chain the output using ';' to perform multiple replacements.<br/>
|
||||
* If the regexp contains capturing groups, a find operation would only retain those; for a replace operation, the replacement string can refer to capturing groups with a syntax like '$1'.
|
||||
*/
|
||||
public static String applySedRegularExpression(String text, String regex) {
|
||||
String originalRegEx = regex;
|
||||
if(!regex.startsWith("/")) {
|
||||
throw new IllegalArgumentException("Invalid expression format: " + originalRegEx);
|
||||
}
|
||||
regex = regex.substring(1);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char[] chars = regex.toCharArray();
|
||||
int index1 = -1;
|
||||
int index2 = -1;
|
||||
for(int i=0; i<chars.length; i++) {
|
||||
char c = chars[i];
|
||||
switch(c) {
|
||||
case ';':
|
||||
text = applySedRegularExpression(sb.toString(), text, originalRegEx, index1, index2);
|
||||
index1 = -1;
|
||||
index2 = -1;
|
||||
sb = new StringBuilder();
|
||||
i++;
|
||||
if(i >= chars.length || chars[i] != '/') {
|
||||
throw new IllegalArgumentException("Invalid expression format: " + originalRegEx);
|
||||
}
|
||||
break;
|
||||
case '\\':
|
||||
i++;
|
||||
if(i >= chars.length) {
|
||||
throw new IllegalArgumentException("Invalid expression format: " + originalRegEx);
|
||||
}
|
||||
switch(chars[i]) {
|
||||
case '/': sb.append('/'); break;
|
||||
case ';': sb.append(';'); break;
|
||||
default: sb.append('\\').append(chars[i]); break;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
if(index1 == -1) {
|
||||
index1 = sb.length();
|
||||
} else if(index2 == -1) {
|
||||
index2 = sb.length();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid expression format: " + originalRegEx);
|
||||
}
|
||||
break;
|
||||
default: sb.append(c); break;
|
||||
}
|
||||
}
|
||||
if(index1 == -1) {
|
||||
throw new IllegalArgumentException("Invalid expression format: " + originalRegEx);
|
||||
}
|
||||
return applySedRegularExpression(sb.toString(), text, originalRegEx, index1, index2);
|
||||
}
|
||||
|
||||
private static String applySedRegularExpression(String s, String text, String originalRegEx, int index1, int index2) {
|
||||
StringBuilder sb;
|
||||
String toFind = s.substring(0, index1);
|
||||
String replacement = index2 == -1? null: s.substring(index1, index2);
|
||||
String modifiers = index2 == -1? s.substring(index1): s.substring(index2);
|
||||
boolean isGlobal = false;
|
||||
int flags = 0;
|
||||
for(int i=0; i<modifiers.length(); i++) {
|
||||
char c = modifiers.charAt(i);
|
||||
switch(c) {
|
||||
case 'g': isGlobal = true; break;
|
||||
case 'i': flags |= Pattern.CASE_INSENSITIVE; break;
|
||||
case 'd': flags |= Pattern.UNIX_LINES; break;
|
||||
case 'm': flags |= Pattern.MULTILINE; break;
|
||||
case 's': flags |= Pattern.DOTALL; break;
|
||||
case 'u': flags |= Pattern.UNICODE_CASE; break;
|
||||
case 'x': flags |= Pattern.COMMENTS; break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid expression format: " + originalRegEx);
|
||||
}
|
||||
}
|
||||
Matcher matcher = Pattern.compile(toFind, flags).matcher(text);
|
||||
if(replacement == null) {
|
||||
// Just returning the matches, no replacement
|
||||
int groupCount = matcher.groupCount();
|
||||
sb = new StringBuilder();
|
||||
while(matcher.find()) {
|
||||
if(groupCount > 0) {
|
||||
for(int i=0; i<groupCount; i++) {
|
||||
String group = matcher.group(i + 1);
|
||||
if(group != null) {
|
||||
sb.append(group);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String group = matcher.group();
|
||||
if(group != null) {
|
||||
sb.append(group);
|
||||
}
|
||||
}
|
||||
if(!isGlobal) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
if(isGlobal) {
|
||||
return matcher.replaceAll(replacement);
|
||||
}
|
||||
return matcher.replaceFirst(replacement);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -36,6 +36,10 @@
|
||||
*/
|
||||
package org.jooq.debug.console.remote;
|
||||
|
||||
import org.jooq.debug.Breakpoint;
|
||||
import org.jooq.debug.BreakpointAfterExecutionHit;
|
||||
import org.jooq.debug.BreakpointBeforeExecutionHit;
|
||||
import org.jooq.debug.BreakpointHitHandler;
|
||||
import org.jooq.debug.Debugger;
|
||||
import org.jooq.debug.LoggingListener;
|
||||
import org.jooq.debug.QueryLoggingData;
|
||||
@ -62,29 +66,78 @@ public class ClientDebugger implements Debugger {
|
||||
}
|
||||
|
||||
private LoggingListener loggingListener;
|
||||
private final Object LOGGING_LISTENER_LOCK = new Object();
|
||||
|
||||
@Override
|
||||
public void setLoggingListener(LoggingListener loggingListener) {
|
||||
this.loggingListener = loggingListener;
|
||||
synchronized (LOGGING_LISTENER_LOCK) {
|
||||
this.loggingListener = loggingListener;
|
||||
}
|
||||
new ServerDebugger.CMS_setLoggingActive().asyncExec(communicationInterface, loggingListener != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoggingListener getLoggingListener() {
|
||||
return loggingListener;
|
||||
synchronized (LOGGING_LISTENER_LOCK) {
|
||||
return loggingListener;
|
||||
}
|
||||
}
|
||||
|
||||
private StatementMatcher[] loggingStatementMatchers;
|
||||
private final Object LOGGING_STATEMENT_MATCHERS_LOCK = new Object();
|
||||
|
||||
@Override
|
||||
public void setLoggingStatementMatchers(StatementMatcher[] loggingStatementMatchers) {
|
||||
this.loggingStatementMatchers = loggingStatementMatchers;
|
||||
synchronized (LOGGING_STATEMENT_MATCHERS_LOCK) {
|
||||
this.loggingStatementMatchers = loggingStatementMatchers;
|
||||
}
|
||||
new ServerDebugger.CMS_setLoggingStatementMatchers().asyncExec(communicationInterface, (Object)loggingStatementMatchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatementMatcher[] getLoggingStatementMatchers() {
|
||||
return loggingStatementMatchers;
|
||||
synchronized (LOGGING_STATEMENT_MATCHERS_LOCK) {
|
||||
return loggingStatementMatchers;
|
||||
}
|
||||
}
|
||||
|
||||
private Breakpoint[] breakpoints;
|
||||
private final Object BREAKPOINT_LOCK = new Object();
|
||||
|
||||
@Override
|
||||
public void setBreakpoints(Breakpoint[] breakpoints) {
|
||||
if(breakpoints != null && breakpoints.length == 0) {
|
||||
breakpoints = null;
|
||||
}
|
||||
synchronized (BREAKPOINT_LOCK) {
|
||||
this.breakpoints = breakpoints;
|
||||
}
|
||||
new ServerDebugger.CMS_setBreakpoints().asyncExec(communicationInterface, (Object)breakpoints);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Breakpoint[] getBreakpoints() {
|
||||
synchronized (BREAKPOINT_LOCK) {
|
||||
return breakpoints;
|
||||
}
|
||||
}
|
||||
|
||||
private BreakpointHitHandler breakpointHitHandler;
|
||||
private final Object BREAKPOINT_HIT_HANDLER_LOCK = new Object();
|
||||
|
||||
@Override
|
||||
public void setBreakpointHitHandler(BreakpointHitHandler breakpointHitHandler) {
|
||||
synchronized (BREAKPOINT_HIT_HANDLER_LOCK) {
|
||||
this.breakpointHitHandler = breakpointHitHandler;
|
||||
}
|
||||
new ServerDebugger.CMS_setBreakpointHitHandlerActive().asyncExec(communicationInterface, breakpointHitHandler != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BreakpointHitHandler getBreakpointHitHandler() {
|
||||
synchronized (BREAKPOINT_HIT_HANDLER_LOCK) {
|
||||
return breakpointHitHandler;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -107,7 +160,7 @@ public class ClientDebugger implements Debugger {
|
||||
if(loggingListener != null) {
|
||||
loggingListener.logQueries((QueryLoggingData)args[0]);
|
||||
}
|
||||
return 1;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,4 +176,35 @@ public class ClientDebugger implements Debugger {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class CMC_processBreakpointBeforeExecutionHit extends ClientDebuggerCommandMessage {
|
||||
@Override
|
||||
public Object run(Object[] args) {
|
||||
BreakpointHitHandler breakpointHitHandler = getDebugger().getBreakpointHitHandler();
|
||||
if(breakpointHitHandler != null) {
|
||||
BreakpointBeforeExecutionHit breakpointHit = (BreakpointBeforeExecutionHit)args[0];
|
||||
breakpointHitHandler.processBreakpointBeforeExecutionHit(breakpointHit);
|
||||
if(breakpointHit.getBreakpointID() != null) {
|
||||
// The breakpoint was not processed, so we process it here.
|
||||
breakpointHit.setExecutionType(BreakpointBeforeExecutionHit.ExecutionType.RUN, null);
|
||||
}
|
||||
return breakpointHit;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class CMC_processBreakpointAfterExecutionHit extends ClientDebuggerCommandMessage {
|
||||
@Override
|
||||
public Object run(Object[] args) {
|
||||
BreakpointHitHandler breakpointHitHandler = getDebugger().getBreakpointHitHandler();
|
||||
if(breakpointHitHandler != null) {
|
||||
BreakpointAfterExecutionHit breakpointHit = (BreakpointAfterExecutionHit)args[0];
|
||||
breakpointHitHandler.processBreakpointAfterExecutionHit(breakpointHit);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -38,6 +38,9 @@ package org.jooq.debug.console.remote;
|
||||
|
||||
import org.jooq.debug.console.remote.messaging.CommandMessage;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
abstract class ClientDebuggerCommandMessage extends CommandMessage {
|
||||
|
||||
|
||||
@ -39,6 +39,9 @@ package org.jooq.debug.console.remote;
|
||||
import org.jooq.debug.Debugger;
|
||||
import org.jooq.debug.console.remote.messaging.CommunicationInterface;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
class DebuggerCommmunicationInterface extends CommunicationInterface {
|
||||
|
||||
private Debugger debugger;
|
||||
|
||||
@ -36,6 +36,10 @@
|
||||
*/
|
||||
package org.jooq.debug.console.remote;
|
||||
|
||||
import org.jooq.debug.Breakpoint;
|
||||
import org.jooq.debug.BreakpointAfterExecutionHit;
|
||||
import org.jooq.debug.BreakpointBeforeExecutionHit;
|
||||
import org.jooq.debug.BreakpointHitHandler;
|
||||
import org.jooq.debug.LocalDebugger;
|
||||
import org.jooq.debug.LoggingListener;
|
||||
import org.jooq.debug.QueryLoggingData;
|
||||
@ -44,6 +48,9 @@ import org.jooq.debug.StatementMatcher;
|
||||
import org.jooq.debug.console.DatabaseDescriptor;
|
||||
import org.jooq.debug.console.remote.messaging.CommunicationInterface;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
class ServerDebugger extends LocalDebugger {
|
||||
|
||||
public ServerDebugger(DatabaseDescriptor databaseDescriptor) {
|
||||
@ -82,6 +89,26 @@ class ServerDebugger extends LocalDebugger {
|
||||
}
|
||||
}
|
||||
|
||||
private void setBreakpointHitHandlerActive(boolean isActive) {
|
||||
if(isActive) {
|
||||
setBreakpointHitHandler(new BreakpointHitHandler() {
|
||||
@Override
|
||||
public void processBreakpointBeforeExecutionHit(BreakpointBeforeExecutionHit breakpointHit) {
|
||||
BreakpointBeforeExecutionHit modifiedBreakpointHit = (BreakpointBeforeExecutionHit)new ClientDebugger.CMC_processBreakpointBeforeExecutionHit().syncExec(communicationInterface, breakpointHit);
|
||||
if(modifiedBreakpointHit != null) {
|
||||
breakpointHit.setExecutionType(modifiedBreakpointHit.getExecutionType(), modifiedBreakpointHit.getSql());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void processBreakpointAfterExecutionHit(BreakpointAfterExecutionHit breakpointHit) {
|
||||
new ClientDebugger.CMC_processBreakpointAfterExecutionHit().syncExec(communicationInterface, breakpointHit);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setBreakpointHitHandler(null);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class CMS_setLoggingStatementMatchers extends ServerDebuggerCommandMessage {
|
||||
@Override
|
||||
@ -91,4 +118,22 @@ class ServerDebugger extends LocalDebugger {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class CMS_setBreakpoints extends ServerDebuggerCommandMessage {
|
||||
@Override
|
||||
public Object run(Object[] args) {
|
||||
getDebugger().setBreakpoints((Breakpoint[])args[0]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class CMS_setBreakpointHitHandlerActive extends ServerDebuggerCommandMessage {
|
||||
@Override
|
||||
public Object run(Object[] args) {
|
||||
getDebugger().setBreakpointHitHandlerActive((Boolean)args[0]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -38,6 +38,9 @@ package org.jooq.debug.console.remote;
|
||||
|
||||
import org.jooq.debug.console.remote.messaging.CommandMessage;
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
abstract class ServerDebuggerCommandMessage extends CommandMessage {
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* The native interface, which establishes the link between a peer VM and this local side.
|
||||
* The communication interface, which establishes the link between a peer VM and this local side.
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public class CommunicationInterface {
|
||||
|
||||
@ -37,6 +37,9 @@
|
||||
package org.jooq.debug.console.remote.messaging;
|
||||
|
||||
|
||||
/**
|
||||
* @author Christopher Deckers
|
||||
*/
|
||||
public interface CommunicationInterfaceFactory {
|
||||
|
||||
public CommunicationInterface createCommunicationInterface(int port);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user