Skip to content

Commit e3de8de

Browse files
committed
Refactored Reporter, ReporterFactory and OutputBuffers to be more
clean and working with new reporter API
1 parent 2593fd7 commit e3de8de

File tree

10 files changed

+204
-151
lines changed

10 files changed

+204
-151
lines changed

src/main/java/org/utplsql/api/TestRunner.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,6 @@ else if (e.getErrorCode() == UtPLSQLNotInstalledException.ERROR_CODE) {
129129
throw new UtPLSQLNotInstalledException(e);
130130
}
131131
else {
132-
// If the execution failed by unexpected reasons finishes all reporters,
133-
// this way the users don't need to care about reporters' sessions hanging.
134-
OracleConnection oraConn = conn.unwrap(OracleConnection.class);
135-
136-
try (CallableStatement closeBufferStmt = conn.prepareCall("BEGIN ut_output_buffer.close(?); END;")) {
137-
closeBufferStmt.setArray(1, oraConn.createOracleArray(CustomTypes.UT_REPORTERS, options.reporterList.toArray()));
138-
closeBufferStmt.execute();
139-
} catch (SQLException ignored) {}
140-
141132
throw e;
142133
}
143134
} finally {
@@ -156,7 +147,7 @@ else if (e.getErrorCode() == UtPLSQLNotInstalledException.ERROR_CODE) {
156147
* @throws SQLException any sql exception
157148
*/
158149
private void validateReporter(Connection conn, Reporter reporter) throws SQLException {
159-
if (reporter.getId() == null || reporter.getId().isEmpty())
150+
if (!reporter.isInit() || reporter.getId() == null || reporter.getId().isEmpty())
160151
reporter.init(conn);
161152
}
162153

Original file line numberDiff line numberDiff line change
@@ -1,25 +1,37 @@
1-
package org.utplsql.api;
1+
package org.utplsql.api.outputBuffer;
22

3+
import oracle.jdbc.OracleCallableStatement;
4+
import oracle.jdbc.OracleConnection;
5+
import oracle.jdbc.OraclePreparedStatement;
36
import org.utplsql.api.reporter.Reporter;
47
import oracle.jdbc.OracleTypes;
58

9+
import javax.xml.transform.Result;
610
import java.io.PrintStream;
711
import java.sql.*;
812
import java.util.ArrayList;
913
import java.util.List;
14+
import java.util.function.Consumer;
1015

1116
/**
1217
* Fetches the lines produced by a reporter.
18+
*
19+
* @author vinicius
20+
* @author pesse
1321
*/
14-
public class OutputBuffer {
22+
public class DefaultOutputBuffer implements OutputBuffer {
1523

1624
private Reporter reporter;
1725

1826
/**
19-
* Creates a new OutputBuffer.
27+
* Creates a new DefaultOutputBuffer.
2028
* @param reporter the reporter to be used
2129
*/
22-
public OutputBuffer(Reporter reporter) {
30+
public DefaultOutputBuffer(Reporter reporter) {
31+
32+
assert reporter.isInit() : "Reporter is not initialized! You can only create OutputBuffers for initialized Reporters";
33+
assert reporter.hasOutput() : "Reporter has no output. Please use NonOutputBuffer instead";
34+
2335
this.reporter = reporter;
2436
}
2537

@@ -59,24 +71,20 @@ public void printAvailable(Connection conn, List<PrintStream> printStreams) thro
5971
/**
6072
* Print the lines as soon as they are produced and call the callback passing the new line.
6173
* @param conn DB connection
62-
* @param cb the callback to be called
74+
* @param onLineFetched the callback to be called
6375
* @throws SQLException any sql errors
6476
*/
65-
public void fetchAvailable(Connection conn, Callback cb) throws SQLException {
66-
PreparedStatement preparedStatement = null;
67-
ResultSet resultSet = null;
68-
try {
69-
preparedStatement = conn.prepareStatement("SELECT * FROM table(ut_output_buffer.get_lines(?))");
70-
preparedStatement.setString(1, getReporter().getId());
71-
resultSet = preparedStatement.executeQuery();
72-
73-
while (resultSet.next())
74-
cb.onLineFetched(resultSet.getString(1));
75-
} finally {
76-
if (resultSet != null)
77-
resultSet.close();
78-
if (preparedStatement != null)
79-
preparedStatement.close();
77+
public void fetchAvailable(Connection conn, Consumer<String> onLineFetched) throws SQLException {
78+
79+
OracleConnection oraConn = conn.unwrap(OracleConnection.class);
80+
81+
try (OraclePreparedStatement pstmt = (OraclePreparedStatement)oraConn.prepareStatement("select * from table(?.get_lines())")) {
82+
83+
pstmt.setORAData(1, getReporter());
84+
try (ResultSet resultSet = pstmt.executeQuery() ) {
85+
while (resultSet.next())
86+
onLineFetched.accept(resultSet.getString(1));
87+
}
8088
}
8189
}
8290

@@ -87,34 +95,25 @@ public void fetchAvailable(Connection conn, Callback cb) throws SQLException {
8795
* @throws SQLException any sql errors
8896
*/
8997
public List<String> fetchAll(Connection conn) throws SQLException {
90-
CallableStatement callableStatement = null;
91-
ResultSet resultSet = null;
92-
try {
93-
callableStatement = conn.prepareCall("BEGIN ? := ut_output_buffer.get_lines_cursor(?); END;");
94-
callableStatement.registerOutParameter(1, OracleTypes.CURSOR);
95-
callableStatement.setString(2, getReporter().getId());
96-
callableStatement.execute();
97-
98-
resultSet = (ResultSet) callableStatement.getObject(1);
99-
100-
List<String> outputLines = new ArrayList<>();
101-
while (resultSet.next()) {
102-
outputLines.add(resultSet.getString("text"));
98+
99+
OracleConnection oraConn = conn.unwrap(OracleConnection.class);
100+
101+
try (OracleCallableStatement cstmt = (OracleCallableStatement)oraConn.prepareCall("{? = call ?.get_lines_cursor() }")) {
102+
103+
cstmt.registerOutParameter(1, OracleTypes.CURSOR);
104+
cstmt.setORAData(2, getReporter());
105+
106+
cstmt.execute();
107+
108+
try ( ResultSet resultSet = (ResultSet) cstmt.getObject(1)) {
109+
110+
List<String> outputLines = new ArrayList<>();
111+
while (resultSet.next()) {
112+
outputLines.add(resultSet.getString("text"));
113+
}
114+
return outputLines;
103115
}
104-
return outputLines;
105-
} finally {
106-
if (resultSet != null)
107-
resultSet.close();
108-
if (callableStatement != null)
109-
callableStatement.close();
110116
}
111117
}
112118

113-
/**
114-
* Callback to be called when a new line is available from the output buffer.
115-
*/
116-
public interface Callback {
117-
void onLineFetched(String s);
118-
}
119-
120119
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package org.utplsql.api.outputBuffer;
2+
3+
import org.utplsql.api.reporter.Reporter;
4+
5+
import java.io.PrintStream;
6+
import java.sql.Connection;
7+
import java.sql.SQLException;
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
import java.util.function.Consumer;
11+
12+
/** An OutputBuffer replacement which just returns nothing at all. Suitable for Reporters without any output
13+
*
14+
* @author pesse
15+
*/
16+
public class NonOutputBuffer implements OutputBuffer {
17+
18+
private Reporter reporter;
19+
20+
public NonOutputBuffer( Reporter reporter) {
21+
this.reporter = reporter;
22+
}
23+
24+
@Override
25+
public Reporter getReporter() {
26+
return reporter;
27+
}
28+
29+
@Override
30+
public void printAvailable(Connection conn, PrintStream ps) throws SQLException {
31+
List<PrintStream> printStreams = new ArrayList<>(1);
32+
printStreams.add(ps);
33+
printAvailable(conn, printStreams);
34+
}
35+
36+
@Override
37+
public void printAvailable(Connection conn, List<PrintStream> printStreams) throws SQLException {
38+
fetchAvailable(conn, s -> {
39+
for (PrintStream ps : printStreams)
40+
ps.println(s);
41+
});
42+
}
43+
44+
@Override
45+
public void fetchAvailable(Connection conn, Consumer<String> onLineFetched) throws SQLException {
46+
onLineFetched.accept(null);
47+
}
48+
49+
@Override
50+
public List<String> fetchAll(Connection conn) throws SQLException {
51+
return new ArrayList<>();
52+
}
53+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.utplsql.api.outputBuffer;
2+
3+
import org.utplsql.api.reporter.Reporter;
4+
5+
import java.io.PrintStream;
6+
import java.sql.Connection;
7+
import java.sql.SQLException;
8+
import java.util.List;
9+
import java.util.function.Consumer;
10+
11+
public interface OutputBuffer {
12+
13+
Reporter getReporter();
14+
15+
/**
16+
* Print the lines as soon as they are produced and write to a PrintStream.
17+
* @param conn DB connection
18+
* @param ps the PrintStream to be used, e.g: System.out
19+
* @throws SQLException any sql errors
20+
*/
21+
void printAvailable(Connection conn, PrintStream ps) throws SQLException;
22+
23+
/**
24+
* Print the lines as soon as they are produced and write to a list of PrintStreams.
25+
* @param conn DB connection
26+
* @param printStreams the PrintStream list to be used, e.g: System.out, new PrintStream(new FileOutputStream)
27+
* @throws SQLException any sql errors
28+
*/
29+
void printAvailable(Connection conn, List<PrintStream> printStreams) throws SQLException;
30+
31+
/**
32+
* Print the lines as soon as they are produced and call the callback passing the new line.
33+
* @param conn DB connection
34+
* @param onLineFetched the callback to be called
35+
* @throws SQLException any sql errors
36+
*/
37+
void fetchAvailable(Connection conn, Consumer<String> onLineFetched) throws SQLException;
38+
39+
/**
40+
* Get all lines from output buffer and return it as a list of strings.
41+
* @param conn DB connection
42+
* @return the lines
43+
* @throws SQLException any sql errors
44+
*/
45+
List<String> fetchAll(Connection conn) throws SQLException;
46+
47+
}

src/main/java/org/utplsql/api/reporter/DefaultReporters.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.utplsql.api.reporter;
22

33
import java.util.function.BiFunction;
4-
import java.util.function.Supplier;
54

65
/** This enum defines default reporters, added and maintained by the utPLSQL team, and their (default) factory method
76
*

src/main/java/org/utplsql/api/reporter/Reporter.java

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
import oracle.sql.ORAData;
88
import oracle.sql.STRUCT;
99
import oracle.sql.StructDescriptor;
10+
import org.utplsql.api.outputBuffer.DefaultOutputBuffer;
11+
import org.utplsql.api.outputBuffer.NonOutputBuffer;
12+
import org.utplsql.api.outputBuffer.OutputBuffer;
1013

1114
import java.sql.*;
1215

@@ -31,10 +34,6 @@ private void setTypeName( String typeName ) {
3134
this.selfType = typeName.replaceAll("[^0-9a-zA-Z_]", "");
3235
}
3336

34-
public void setParameters( Object[] parameters ) {
35-
// Empty method
36-
}
37-
3837
public Reporter init( Connection con ) throws SQLException {
3938

4039
OracleConnection oraConn = con.unwrap(OracleConnection.class);
@@ -48,7 +47,7 @@ public Reporter init( Connection con ) throws SQLException {
4847
}
4948

5049
/** Initializes the Reporter from database
51-
* This is necessary because we set up OutputBuffer (and maybe other stuff) we don't want to know and care about
50+
* This is necessary because we set up DefaultOutputBuffer (and maybe other stuff) we don't want to know and care about
5251
* in the java API. Let's just do the instantiation of the Reporter in the database and map it into this object.
5352
*
5453
* @param oraConn
@@ -70,18 +69,24 @@ private void initDbReporter( OracleConnection oraConn ) throws SQLException {
7069
* @throws SQLException
7170
*/
7271
private void initHasOutput( OracleConnection oraConn ) throws SQLException {
73-
OracleCallableStatement cstmt = (OracleCallableStatement)oraConn.prepareCall("{? = call ?.has_output()}");
74-
75-
cstmt.registerOutParameter(1, OracleTypes.INTEGER);
76-
cstmt.setORAData(2, this);
77-
cstmt.execute();
7872

79-
Integer i = cstmt.getInt(1);
80-
if ( i != null && i == 1 ) {
81-
hasOutput = true;
82-
}
83-
else {
84-
hasOutput = false;
73+
try ( PreparedStatement stmt = oraConn.prepareStatement("select ut_runner.is_output_reporter(?) from dual")) {
74+
stmt.setString(1, getTypeName());
75+
76+
try ( ResultSet rs = stmt.executeQuery() ) {
77+
if ( rs.next() ) {
78+
String isReporterResult = rs.getString(1);
79+
80+
if ( isReporterResult == null )
81+
throw new IllegalArgumentException("The given type " + getTypeName() + " is not a valid Reporter!");
82+
else if (isReporterResult.equalsIgnoreCase("Y") )
83+
hasOutput = true;
84+
else
85+
hasOutput = false;
86+
}
87+
else
88+
throw new SQLException("Could not check Reporter validity");
89+
}
8590
}
8691
}
8792

@@ -120,4 +125,13 @@ public Datum toDatum(Connection c) throws SQLException
120125
return new STRUCT(sd, c, getAttributes());
121126
}
122127

128+
public OutputBuffer getOutputBuffer() {
129+
130+
if ( hasOutput() ) {
131+
return new DefaultOutputBuffer(this);
132+
}
133+
else {
134+
return new NonOutputBuffer(this);
135+
}
136+
}
123137
}

src/main/java/org/utplsql/api/reporter/ReporterFactory.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
*/
2020
public final class ReporterFactory implements ORADataFactory {
2121

22-
23-
2422
public static class ReporterInfo {
2523
public ReporterInfo(BiFunction<String, Object[], ? extends Reporter> factoryMethod, String description) {
2624
this.factoryMethod = factoryMethod;
@@ -55,6 +53,14 @@ public static ReporterFactory getInstance() {
5553
return instance;
5654
}
5755

56+
public static Reporter create( DefaultReporters reporter ) {
57+
return getInstance().createReporter(reporter);
58+
}
59+
60+
public static Reporter create( String reporter ) {
61+
return getInstance().createReporter(reporter);
62+
}
63+
5864
/** Registers a creation method for a specified reporter name. Overrides eventually existing creation method
5965
*
6066
* @param reporterName the reporter's name to register
@@ -84,7 +90,7 @@ public synchronized ReporterInfo unregisterReporterFactoryMethod( String reporte
8490
*/
8591
public Reporter createReporter(String reporterName, Object[] attributes) {
8692

87-
BiFunction<String, Object[], ? extends Reporter> supplier = getDefaultReporterFactoryMethod();
93+
BiFunction<String, Object[], ? extends Reporter> supplier = Reporter::new;
8894

8995
if ( reportFactoryMethodMap.containsKey(reporterName)) {
9096

@@ -108,6 +114,15 @@ public Reporter createReporter( String reporterName ) {
108114
return createReporter(reporterName, null);
109115
}
110116

117+
/** Returns a new reporter of the given DefaultReporter type
118+
*
119+
* @param reporter
120+
* @return
121+
*/
122+
public Reporter createReporter( DefaultReporters reporter ) {
123+
return createReporter(reporter.name());
124+
}
125+
111126
/** Returns a set of all registered reporter's names
112127
*
113128
* @return Set of reporter names

0 commit comments

Comments
 (0)