Skip to content

Commit bcbcd9f

Browse files
Merge pull request #2 from mendix/feature/support-only-mendix-datatypes
Feature/support only mendix datatypes
2 parents b7f3016 + 5fc2f82 commit bcbcd9f

26 files changed

+788
-266
lines changed

DatabaseConnector.mpr

80 KB
Binary file not shown.

javasource/databaseconnector/actions/ExecuteQuery.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.mendix.logging.ILogNode;
1717
import com.mendix.systemwideinterfaces.core.IContext;
1818
import com.mendix.systemwideinterfaces.core.IMendixObject;
19+
import com.mendix.systemwideinterfaces.core.meta.IMetaObject;
1920
import com.mendix.webui.CustomJavaAction;
2021
import databaseconnector.impl.JdbcConnector;
2122

@@ -76,11 +77,11 @@ public ExecuteQuery(IContext context, String jdbcUrl, String userName, String pa
7677
public java.util.List<IMendixObject> executeAction() throws Exception
7778
{
7879
// BEGIN USER CODE
79-
String entityName = resultObject.getMetaObject().getName();
80+
IMetaObject metaObject = resultObject.getMetaObject();
8081
Stream<IMendixObject> resultStream = connector.executeQuery(
81-
this.jdbcUrl, this.userName, this.password, entityName, this.sql, this.getContext());
82+
this.jdbcUrl, this.userName, this.password, metaObject, this.sql, this.getContext());
8283
List<IMendixObject> resultList = resultStream.collect(Collectors.toList());
83-
logNode.info(String.format("List: %d", resultList.size()));
84+
logNode.trace(String.format("Result list count: %d", resultList.size()));
8485

8586
return resultList;
8687
// END USER CODE

javasource/databaseconnector/actions/ExecuteQueryToJson.java

Lines changed: 0 additions & 91 deletions
This file was deleted.
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package databaseconnector.impl;
22

3+
import com.mendix.systemwideinterfaces.core.meta.IMetaPrimitive.PrimitiveType;
4+
35
public class ColumnInfo {
4-
private int index;
5-
private String name;
6+
private final int index;
7+
private final String name;
8+
private final PrimitiveType type;
69

7-
public ColumnInfo(int index, String name) {
10+
public ColumnInfo(final int index, final String name, final PrimitiveType type) {
811
this.index = index;
912
this.name = name;
13+
this.type = type;
1014
}
1115

1216
public int getIndex() {
@@ -16,4 +20,8 @@ public int getIndex() {
1620
public String getName() {
1721
return name;
1822
}
23+
24+
public PrimitiveType getType() {
25+
return type;
26+
}
1927
}

javasource/databaseconnector/impl/JdbcConnectionManager.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ public Connection getConnection(final String jdbcUrl, final String userName, fin
4343

4444
final Integer connPoolKey = toConnPoolKey(jdbcUrl, userName);
4545
final HikariDataSource dataSource = connectionPool.computeIfAbsent(connPoolKey, k -> {
46-
logNode.info(String.format("Creating data source in connection pool for [url=%s, user=%s]", jdbcUrl, userName));
46+
logNode.trace(String.format("Creating data source in connection pool for [url=%s, user=%s]", jdbcUrl, userName));
4747
return createHikariDataSource(jdbcUrl, userName, password);
4848
});
49-
logNode.info(String.format("Getting connection from data source in connection pool for [url=%s, user=%s]", jdbcUrl, userName));
49+
logNode.trace(String.format("Getting connection from data source in connection pool for [url=%s, user=%s]", jdbcUrl, userName));
5050
return dataSource.getConnection();
5151
}
5252

@@ -61,7 +61,7 @@ private synchronized void initializeDrivers() {
6161
ServiceLoader<Driver> loader = ServiceLoader.load(Driver.class);
6262
Stream<String> driverNames = StreamSupport.stream(loader.spliterator(), false).map(a -> a.getClass().getName());
6363
String logMessage = driverNames.collect(Collectors.joining(", ", "Found JDBC Drivers: ", ""));
64-
logNode.info(logMessage);
64+
logNode.trace(logMessage);
6565
hasDriversInitialized = true;
6666
}
6767
}

javasource/databaseconnector/impl/JdbcConnector.java

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,93 @@
11
package databaseconnector.impl;
22

3+
import java.io.ByteArrayInputStream;
34
import java.sql.Connection;
45
import java.sql.PreparedStatement;
56
import java.sql.ResultSet;
67
import java.sql.SQLException;
78
import java.util.Map;
9+
import java.util.Optional;
10+
import java.util.function.BiConsumer;
811
import java.util.function.Function;
9-
import java.util.stream.Collectors;
12+
import java.util.function.Supplier;
1013
import java.util.stream.Stream;
1114

12-
import org.json.JSONArray;
13-
import org.json.JSONObject;
14-
15+
import com.mendix.core.objectmanagement.member.MendixHashString;
1516
import com.mendix.logging.ILogNode;
1617
import com.mendix.systemwideinterfaces.core.IContext;
1718
import com.mendix.systemwideinterfaces.core.IMendixObject;
19+
import com.mendix.systemwideinterfaces.core.meta.IMetaObject;
20+
import com.mendix.systemwideinterfaces.core.meta.IMetaPrimitive.PrimitiveType;
1821

1922
import databaseconnector.interfaces.ConnectionManager;
2023
import databaseconnector.interfaces.ObjectInstantiator;
2124

25+
/**
26+
* JdbcConnector implements the execute query (and execute statement) functionality, and returns a {@link Stream} of {@link IMendixObject}s.
27+
*/
2228
public class JdbcConnector {
2329
private final ILogNode logNode;
24-
private ObjectInstantiator objectInstantiator;
25-
private ConnectionManager connectionManager;
30+
private final ObjectInstantiator objectInstantiator;
31+
private final ConnectionManager connectionManager;
2632

27-
public JdbcConnector(final ILogNode logNode, ObjectInstantiator objectInstantiator, ConnectionManager connectionManager) {
33+
public JdbcConnector(final ILogNode logNode, final ObjectInstantiator objectInstantiator, final ConnectionManager connectionManager) {
2834
this.logNode = logNode;
2935
this.objectInstantiator = objectInstantiator;
3036
this.connectionManager = connectionManager;
3137
}
3238

33-
public JdbcConnector(ILogNode logNode) {
39+
public JdbcConnector(final ILogNode logNode) {
3440
this(logNode, new ObjectInstantiatorImpl(), ConnectionManagerSingleton.getInstance());
3541
}
3642

37-
public Stream<IMendixObject> executeQuery(String jdbcUrl, String userName, String password, String entityName, String sql,
38-
IContext context) throws SQLException {
39-
Function<Map<String, Object>, IMendixObject> toMendixObject = columns -> {
43+
public Stream<IMendixObject> executeQuery(final String jdbcUrl, final String userName, final String password, final IMetaObject metaObject, final String sql,
44+
final IContext context) throws SQLException {
45+
String entityName = metaObject.getName();
46+
47+
Function<Map<String, Optional<Object>>, IMendixObject> toMendixObject = columns -> {
4048
IMendixObject obj = objectInstantiator.instantiate(context, entityName);
41-
columns.forEach((n, v) -> obj.setValue(context, n, v));
42-
logNode.info("obj: " + obj);
49+
50+
BiConsumer<String, Optional<Object>> setMemberValue = (name, value) -> {
51+
PrimitiveType type = metaObject.getMetaPrimitive(name).getType();
52+
// convert to suitable value (different for Binary type)
53+
Function<Object, Object> toSuitableValue = toSuitableValue(type);
54+
// for Boolean type, convert null to false
55+
Supplier<Object> defaultValue = () -> type == PrimitiveType.Boolean ? Boolean.FALSE : null;
56+
// apply two functions declared above
57+
Object convertedValue = value.map(toSuitableValue).orElseGet(defaultValue);
58+
// update object with converted value
59+
if (type == PrimitiveType.HashString)
60+
((MendixHashString) obj.getMember(context, name)).setInitialHash((String) convertedValue);
61+
else
62+
obj.setValue(context, name, convertedValue);
63+
};
64+
65+
columns.forEach(setMemberValue);
66+
logNode.trace("Instantiated object: " + obj);
4367
return obj;
4468
};
4569

46-
Stream<Map<String,Object>> stream = executeQuery(jdbcUrl, userName, password, sql);
47-
48-
return stream.map(toMendixObject);
70+
return executeQuery(jdbcUrl, userName, password, metaObject, sql).map(toMendixObject);
4971
}
5072

51-
public String executeQueryToJson(String jdbcUrl, String userName, String password, String sql, IContext context) throws SQLException {
52-
Stream<Map<String, Object>> stream = executeQuery(jdbcUrl, userName, password, sql);
53-
Stream<JSONObject> jsonObjects = stream.map(JSONObject::new);
54-
55-
return new JSONArray(jsonObjects.collect(Collectors.toList())).toString();
73+
private Function<Object, Object> toSuitableValue(final PrimitiveType type) {
74+
return v -> type == PrimitiveType.Binary ? new ByteArrayInputStream((byte[]) v) : v;
5675
}
5776

58-
public Stream<Map<String, Object>> executeQuery(String jdbcUrl, String userName, String password, String sql) throws SQLException {
59-
logNode.info(String.format("executeQuery: %s, %s, %s", jdbcUrl, userName, sql));
77+
private Stream<Map<String, Optional<Object>>> executeQuery(final String jdbcUrl, final String userName, final String password, final IMetaObject metaObject, final String sql) throws SQLException {
78+
logNode.trace(String.format("executeQuery: %s, %s, %s", jdbcUrl, userName, sql));
6079

6180
try (Connection connection = connectionManager.getConnection(jdbcUrl, userName, password);
6281
PreparedStatement preparedStatement = connection.prepareStatement(sql);
6382
ResultSet resultSet = preparedStatement.executeQuery()) {
64-
ResultSetReader resultSetReader = new ResultSetReader(resultSet);
83+
ResultSetReader resultSetReader = new ResultSetReader(resultSet, metaObject);
6584

6685
return resultSetReader.readAll().stream();
6786
}
6887
}
6988

70-
public long executeStatement(String jdbcUrl, String userName, String password, String sql) throws SQLException {
71-
logNode.info(String.format("executeStatement: %s, %s, %s", jdbcUrl, userName, sql));
89+
public long executeStatement(final String jdbcUrl, final String userName, final String password, final String sql) throws SQLException {
90+
logNode.trace(String.format("executeStatement: %s, %s, %s", jdbcUrl, userName, sql));
7291

7392
try (Connection connection = connectionManager.getConnection(jdbcUrl, userName, password);
7493
PreparedStatement preparedStatement = connection.prepareStatement(sql)) {

javasource/databaseconnector/impl/ObjectInstantiatorImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
class ObjectInstantiatorImpl implements ObjectInstantiator {
1010

1111
@Override
12-
public IMendixObject instantiate(IContext context, String entityName) {
12+
public IMendixObject instantiate(final IContext context, final String entityName) {
1313
return Core.instantiate(context, entityName);
1414
}
1515
}

javasource/databaseconnector/impl/ResultSetIterator.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,30 @@
55
import java.sql.SQLException;
66
import java.util.Iterator;
77
import java.util.List;
8+
import java.util.Optional;
89
import java.util.Spliterator;
910
import java.util.Spliterators;
11+
import java.util.function.Predicate;
1012
import java.util.stream.Collectors;
1113
import java.util.stream.IntStream;
1214
import java.util.stream.Stream;
1315
import java.util.stream.StreamSupport;
1416

17+
import com.mendix.systemwideinterfaces.core.meta.IMetaObject;
18+
import com.mendix.systemwideinterfaces.core.meta.IMetaPrimitive;
19+
1520
/**
1621
* ResultSetIterator implements {@link Iterator} interface. It wraps {@link ResultSet} into a stream for more convenient usage. Along
1722
* with that, it provides information about columns of the given result set.
1823
*/
1924
public class ResultSetIterator implements Iterator<ResultSet> {
20-
2125
private final ResultSet resultSet;
2226
private final List<ColumnInfo> columnInfos;
27+
private final IMetaObject metaObject;
2328

24-
public ResultSetIterator(final ResultSet resultSet) {
29+
public ResultSetIterator(final ResultSet resultSet, final IMetaObject metaObject) {
2530
this.resultSet = resultSet;
31+
this.metaObject = metaObject;
2632
this.columnInfos = createColumnInfos(resultSet);
2733
}
2834

@@ -36,12 +42,24 @@ private List<ColumnInfo> createColumnInfos(final ResultSet resultSet) {
3642
}
3743
}
3844

39-
private ColumnInfo getColumnInfo(int index) {
45+
private ColumnInfo getColumnInfo(final int index) {
46+
final String columnName;
47+
4048
try {
41-
return new ColumnInfo(index, resultSet.getMetaData().getColumnName(index));
49+
columnName = resultSet.getMetaData().getColumnName(index);
4250
} catch (Exception e) {
4351
throw new RuntimeException(e);
4452
}
53+
54+
final Predicate<IMetaPrimitive> caseInsensitiveName = (IMetaPrimitive mp) -> mp.getName().equalsIgnoreCase(columnName);
55+
final Optional<? extends IMetaPrimitive> primitive = metaObject.getMetaPrimitives().stream().filter(caseInsensitiveName).findFirst();
56+
57+
final IMetaPrimitive.PrimitiveType type = primitive.<RuntimeException>orElseThrow(() -> {
58+
final String msg = "The entity type '%s' does not contain the primitive '%s' as specified in the query.";
59+
throw new RuntimeException(String.format(msg, metaObject.getName(), columnName));
60+
}).getType();
61+
62+
return new ColumnInfo(index, columnName, type);
4563
}
4664

4765
@Override

0 commit comments

Comments
 (0)