/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.impl.wsdl.panels.teststeps;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.impl.wsdl.panels.teststeps.support.NamedParameterStatement;
import com.eviware.soapui.impl.wsdl.teststeps.JdbcRequestTestStep;
import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStepWithProperties;
import com.eviware.soapui.model.iface.Request;
import com.eviware.soapui.model.iface.Submit;
import com.eviware.soapui.model.iface.SubmitContext;
import com.eviware.soapui.model.iface.SubmitListener;
import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
import com.eviware.soapui.model.testsuite.TestProperty;
import com.eviware.soapui.support.SoapUIException;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.jdbc.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.Future;
public class JdbcSubmit implements Submit, Runnable {
public static final String JDBC_ERROR = "JDBC_ERROR";
public static final String JDBC_TIMEOUT = "JDBC_TIMEOUT";
private volatile Future<?> future;
private SubmitContext context;
private Status status;
private SubmitListener[] listeners;
private Exception error;
private long timestamp;
protected ResultSet resultSet;
protected PreparedStatement statement;
private Connection connection;
private long timeTaken;
private final JdbcRequest request;
private JdbcResponse response;
private String rawSql;
public JdbcSubmit(JdbcRequest request, SubmitContext submitContext, boolean async) {
this.request = request;
this.context = submitContext;
List<SubmitListener> regListeners = SoapUI.getListenerRegistry().getListeners(SubmitListener.class);
SubmitListener[] submitListeners = request.getSubmitListeners();
this.listeners = new SubmitListener[submitListeners.length + regListeners.size()];
for (int c = 0; c < submitListeners.length; c++) {
this.listeners[c] = submitListeners[c];
}
for (int c = 0; c < regListeners.size(); c++) {
this.listeners[submitListeners.length + c] = regListeners.get(c);
}
error = null;
status = Status.INITIALIZED;
if (async) {
future = SoapUI.getThreadPool().submit(this);
} else {
run();
}
}
public void cancel() {
if (status == Status.CANCELED) {
return;
}
JdbcRequest.logger.info("Canceling request..");
if (status == Status.RUNNING) {
cancelQuery();
}
status = Status.CANCELED;
for (int i = 0; i < listeners.length; i++) {
try {
listeners[i].afterSubmit(this, context);
} catch (Throwable e) {
SoapUI.logError(e);
}
}
}
public Exception getError() {
return error;
}
public Request getRequest() {
return request;
}
public JdbcResponse getResponse() {
return response;
}
public Status getStatus() {
return status;
}
public Status waitUntilFinished() {
if (future != null) {
if (!future.isDone()) {
try {
future.get();
} catch (Exception e) {
SoapUI.logError(e);
}
}
} else {
throw new RuntimeException("cannot wait on null future");
}
return getStatus();
}
public void run() {
try {
for (int i = 0; i < listeners.length; i++) {
if (!listeners[i].beforeSubmit(this, context)) {
status = Status.CANCELED;
System.err.println("listener cancelled submit..");
return;
}
}
status = Status.RUNNING;
runQuery();
if (status != Status.CANCELED) {
status = Status.FINISHED;
}
} catch (Exception e) {
SoapUI.logError(e);
error = e;
} finally {
if (error != null) {
status = Status.ERROR;
}
if (status != Status.CANCELED) {
for (int i = 0; i < listeners.length; i++) {
try {
listeners[i].afterSubmit(this, context);
} catch (Throwable e) {
SoapUI.logError(e);
}
}
}
}
}
private void runQuery() throws Exception {
prepare();
load();
createResponse();
}
public void cancelQuery() {
try {
if (statement != null) {
statement.cancel();
}
} catch (SQLException ex) {
SoapUI.logError(ex);
}
}
private void getDatabaseConnection() throws SQLException, SoapUIException {
JdbcRequestTestStep testStep = request.getTestStep();
connection = JdbcUtils.initConnection(context, testStep.getDriver(), testStep.getConnectionString(),
testStep.getPassword());
// IMPORTANT: setting as readOnly raises an exception in calling stored
// procedures!
// connection.setReadOnly( true );
}
private void load() throws Exception {
try {
JdbcRequestTestStep testStep = request.getTestStep();
if (testStep.isStoredProcedure()) {
timestamp = System.currentTimeMillis();
statement.execute();
} else {
timestamp = System.currentTimeMillis();
statement.execute();
}
timeTaken = System.currentTimeMillis() - timestamp;
if (!StringUtils.isNullOrEmpty(request.getTimeout()) && timeTaken > Long.parseLong(request.getTimeout())) {
context.setProperty(JDBC_TIMEOUT, PropertyExpander.expandProperties(context, request.getTimeout()));
}
} catch (SQLException e) {
context.setProperty(JDBC_ERROR, e);
throw e;
} finally {
timeTaken = System.currentTimeMillis() - timestamp;
}
}
private void prepare() throws Exception {
JdbcRequestTestStep testStep = request.getTestStep();
getDatabaseConnection();
List<TestProperty> props = testStep.getPropertyList();
if (testStep.isStoredProcedure()) {
rawSql = PropertyExpander.expandProperties(context, testStep.getQuery());
if (!rawSql.startsWith("{call ") && !rawSql.endsWith("}")) {
rawSql = "{call " + rawSql + "}";
}
} else {
rawSql = PropertyExpander.expandProperties(context, testStep.getQuery());
}
NamedParameterStatement p = new NamedParameterStatement(connection, rawSql);
for (TestProperty testProperty : props) {
String value = PropertyExpander.expandProperties(context, testProperty.getValue());
if (!testProperty.getName().equals(WsdlTestStepWithProperties.RESPONSE_AS_XML)) {
p.setString(testProperty.getName(), value);
}
}
statement = p.getStatement();
try {
if (!StringUtils.isNullOrEmpty(testStep.getQueryTimeout())) {
String queryTimeout = PropertyExpander.expandProperties(testStep, testStep.getQueryTimeout());
statement.setQueryTimeout(Integer.parseInt(queryTimeout));
}
} catch (NumberFormatException e) {
SoapUI.logError(e, "Problem setting timeout");
}
try {
if (!StringUtils.isNullOrEmpty(testStep.getMaxRows())) {
String maxRows = PropertyExpander.expandProperties(testStep, testStep.getMaxRows());
statement.setMaxRows(Integer.parseInt(maxRows));
}
} catch (NumberFormatException e) {
SoapUI.logError(e, "Problem setting maxRows");
}
try {
if (!StringUtils.isNullOrEmpty(testStep.getFetchSize())) {
String fetchSize = PropertyExpander.expandProperties(testStep, testStep.getFetchSize());
statement.setFetchSize(Integer.parseInt(fetchSize));
}
} catch (NumberFormatException e) {
SoapUI.logError(e, "Problem setting fetchSize");
}
}
public String getRawSql() {
return rawSql;
}
protected String createResponse() {
try {
response = new JdbcResponse(request, statement, rawSql);
response.setTimestamp(timestamp);
response.setTimeTaken(timeTaken);
} catch (Exception e) {
SoapUI.logError(e);
} finally {
try {
if (connection != null) {
connection.close();
}
if (statement != null) {
statement.close();
}
if (resultSet != null) {
resultSet.close();
}
} catch (Exception e) {
}
}
return null;
}
}