Skip to content

Commit f1c4498

Browse files
authored
Merge pull request #3972 from balcirakpeter/fix_sync_attrs
fix(core): fixed attributes parsing for sql group structure sync
2 parents e26b486 + b1abc36 commit f1c4498

File tree

1 file changed

+103
-14
lines changed

1 file changed

+103
-14
lines changed

perun-core/src/main/java/cz/metacentrum/perun/core/impl/ExtSourceSql.java

Lines changed: 103 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
import org.springframework.util.StreamUtils;
1515

1616
import javax.sql.DataSource;
17+
import java.io.ByteArrayOutputStream;
1718
import java.io.IOException;
1819
import java.io.InputStream;
20+
import java.nio.charset.StandardCharsets;
1921
import java.sql.Connection;
2022
import java.sql.PreparedStatement;
2123
import java.sql.ResultSet;
@@ -25,6 +27,7 @@
2527
import java.util.HashMap;
2628
import java.util.List;
2729
import java.util.Map;
30+
import java.util.Objects;
2831

2932
import static cz.metacentrum.perun.core.blImpl.GroupsManagerBlImpl.GROUP_DESCRIPTION;
3033
import static cz.metacentrum.perun.core.blImpl.GroupsManagerBlImpl.GROUP_NAME;
@@ -239,33 +242,29 @@ public List<Map<String, String>> getSubjectGroups(Map<String, String> groupAttri
239242
* @param query to select subject groups
240243
* @return list of subjects
241244
*/
242-
protected List<Map<String,String>> groupQuery(String query) throws InternalErrorException {
245+
protected List<Map<String,String>> groupQuery(String query) {
243246
try (Connection con = getDataSource().getConnection()) {
244247
try (PreparedStatement st = con.prepareStatement(query)) {
245248
try (ResultSet rs = st.executeQuery()) {
246249
List<Map<String, String>> subjects = new ArrayList<>();
247250
log.trace("Query {}", query);
248-
ResultSetMetaData metaData = rs.getMetaData();
249-
List<ColumnMapping> columnMappings = new ArrayList<>(metaData.getColumnCount());
250-
for (int i = 1; i <= metaData.getColumnCount(); i++) {
251-
String columnName = metaData.getColumnLabel(i);
252-
String baseName = matchingGroupColumnName(columnName);
253-
if (baseName != null) {
254-
columnMappings.add(new ColumnMapping(i, baseName, false));
255-
}
256-
}
257251
while (rs.next()) {
258252
Map<String, String> map = new HashMap<>();
259-
for (ColumnMapping columnMapping : columnMappings) {
260-
map.put(columnMapping.attributeName, rs.getString(columnMapping.columnIndex));
261-
}
253+
GROUP_SYNC_DEFAULT_DATA.forEach(
254+
column -> map.put(column, readGroupSyncRequiredData(rs, column))
255+
);
256+
map.putAll(parseAdditionalAttributeData(rs));
262257
subjects.add(map);
263258
}
259+
264260
log.debug("Returning {} subjects from external source {}", subjects.size(), this);
265261
return subjects;
262+
} catch (SQLException e) {
263+
log.error("SQL exception during searching for subject '{}'", query);
264+
throw new InternalErrorException(e);
266265
}
267266
} catch (SQLException e) {
268-
log.error("SQL exception during searching for subject '{}'", query);
267+
log.error("SQL exception during the preparation of query statement '{}'", query);
269268
throw new InternalErrorException(e);
270269
}
271270
} catch (SQLException e) {
@@ -274,6 +273,53 @@ protected List<Map<String,String>> groupQuery(String query) throws InternalError
274273
}
275274
}
276275

276+
/**
277+
* Decodes a full attribute name from the given value. For used mappings,
278+
* see attributeNameMapping.
279+
*
280+
* @param value which will be mapped
281+
* @return attribute full name
282+
*/
283+
private String mapAttributeNames(String value) {
284+
String[] attributeRaw = value.split(":", 3);
285+
String attributeName = null;
286+
if (!ATTRIBUTE_NAME_MAPPING.containsKey(attributeRaw[0])) {
287+
log.warn("Unknown attribute type '{}', attributeRaw {}", attributeRaw[0], attributeRaw);
288+
} else if (!ATTRIBUTE_NAME_MAPPING.containsKey(attributeRaw[1])) {
289+
log.warn("Unknown attribute type '{}', attributeRaw {}", attributeRaw[1], attributeRaw);
290+
} else {
291+
attributeName = ATTRIBUTE_NAME_MAPPING.get(attributeRaw[0]) + ATTRIBUTE_NAME_MAPPING.get(attributeRaw[1]) +
292+
attributeRaw[2];
293+
}
294+
return attributeName;
295+
}
296+
297+
298+
/**
299+
* Parse additional data from the given result set.
300+
*
301+
* @param rs result set with attribute data
302+
* @throws SQLException SQLException
303+
*/
304+
private Map<String, String> parseAdditionalAttributeData(ResultSet rs) throws SQLException {
305+
Map<String, String> additionalAttributes = new HashMap<>();
306+
for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
307+
String columnName = rs.getMetaData().getColumnLabel(i);
308+
if (columnName.contains(":")) {
309+
String attrName = mapAttributeNames(columnName);
310+
String attributeValue;
311+
if (Objects.equals(rs.getMetaData().getColumnTypeName(i), "BLOB")) {
312+
attributeValue = parseBlobValue(rs.getBinaryStream(i), columnName);
313+
} else {
314+
// let driver convert the type to string
315+
attributeValue = rs.getString(i);
316+
}
317+
additionalAttributes.put(attrName, attributeValue);
318+
}
319+
}
320+
return additionalAttributes;
321+
}
322+
277323
protected DataSource getDataSource() {
278324
if (dataSource == null) {
279325
Map<String, String> attributes = this.getAttributes();
@@ -287,4 +333,47 @@ protected DataSource getDataSource() {
287333
return dataSource;
288334
}
289335

336+
/**
337+
* Parse blob value from given input stream.
338+
*
339+
* @param inputStream input stream with a blob value
340+
* @param columnName name of the column to which the blob belongs
341+
* @return parsed value
342+
*/
343+
private String parseBlobValue(InputStream inputStream, String columnName) {
344+
if (inputStream == null) {
345+
return null;
346+
}
347+
try {
348+
ByteArrayOutputStream result = new ByteArrayOutputStream();
349+
byte[] buffer = new byte[1024];
350+
int length;
351+
while ((length = inputStream.read(buffer)) != -1) {
352+
result.write(buffer, 0, length);
353+
}
354+
byte[] bytes = Base64.encodeBase64(result.toByteArray());
355+
return new String(bytes, StandardCharsets.UTF_8);
356+
} catch(IOException ex) {
357+
log.error("Unable to read BLOB for column {}", columnName);
358+
throw new InternalErrorException("Unable to read BLOB data for column: " + columnName, ex);
359+
}
360+
}
361+
362+
/**
363+
* Read data from rs from specified column. If the column doesn't exist,
364+
* a null is returned.
365+
*
366+
* @param rs result rest
367+
* @param column column
368+
* @return column data or null if column doesn't exist
369+
*/
370+
private String readGroupSyncRequiredData(ResultSet rs, String column) {
371+
try {
372+
return rs.getString(column);
373+
} catch (SQLException e) {
374+
// If the column doesn't exist, ignore it
375+
return null;
376+
}
377+
}
378+
290379
}

0 commit comments

Comments
 (0)