]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/storage/Utils.java
aa279a65d68a92fd2acbb9ca14201df930a8f3ef
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / storage / Utils.java
1 package org.asamk.signal.manager.storage;
2
3 import com.fasterxml.jackson.annotation.JsonAutoDetect;
4 import com.fasterxml.jackson.annotation.PropertyAccessor;
5 import com.fasterxml.jackson.core.JsonGenerator;
6 import com.fasterxml.jackson.core.JsonParser;
7 import com.fasterxml.jackson.databind.DeserializationFeature;
8 import com.fasterxml.jackson.databind.JsonNode;
9 import com.fasterxml.jackson.databind.ObjectMapper;
10 import com.fasterxml.jackson.databind.SerializationFeature;
11
12 import org.asamk.signal.manager.storage.recipients.RecipientAddress;
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15 import org.whispersystems.signalservice.api.util.UuidUtil;
16
17 import java.io.InvalidObjectException;
18 import java.sql.PreparedStatement;
19 import java.sql.ResultSet;
20 import java.sql.SQLException;
21 import java.util.Optional;
22 import java.util.Spliterator;
23 import java.util.Spliterators;
24 import java.util.function.Consumer;
25 import java.util.stream.Stream;
26 import java.util.stream.StreamSupport;
27
28 public class Utils {
29
30 private static final Logger logger = LoggerFactory.getLogger(Utils.class);
31
32 private Utils() {
33 }
34
35 public static ObjectMapper createStorageObjectMapper() {
36 final ObjectMapper objectMapper = new ObjectMapper();
37
38 objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.PUBLIC_ONLY);
39 objectMapper.enable(SerializationFeature.INDENT_OUTPUT); // for pretty print
40 objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
41 objectMapper.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
42 objectMapper.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
43
44 return objectMapper;
45 }
46
47 public static JsonNode getNotNullNode(JsonNode parent, String name) throws InvalidObjectException {
48 var node = parent.get(name);
49 if (node == null || node.isNull()) {
50 throw new InvalidObjectException(String.format("Incorrect file format: expected parameter %s not found ",
51 name));
52 }
53
54 return node;
55 }
56
57 public static RecipientAddress getRecipientAddressFromIdentifier(final String identifier) {
58 if (UuidUtil.isUuid(identifier)) {
59 return new RecipientAddress(UuidUtil.parseOrThrow(identifier));
60 } else {
61 return new RecipientAddress(Optional.empty(), Optional.of(identifier));
62 }
63 }
64
65 public static <T> T executeQuerySingleRow(
66 PreparedStatement statement, ResultSetMapper<T> mapper
67 ) throws SQLException {
68 final var resultSet = statement.executeQuery();
69 if (!resultSet.next()) {
70 throw new RuntimeException("Expected a row in result set, but none found.");
71 }
72 return mapper.apply(resultSet);
73 }
74
75 public static <T> Optional<T> executeQueryForOptional(
76 PreparedStatement statement, ResultSetMapper<T> mapper
77 ) throws SQLException {
78 final var resultSet = statement.executeQuery();
79 if (!resultSet.next()) {
80 return Optional.empty();
81 }
82 return Optional.ofNullable(mapper.apply(resultSet));
83 }
84
85 public static <T> Stream<T> executeQueryForStream(
86 PreparedStatement statement, ResultSetMapper<T> mapper
87 ) throws SQLException {
88 final var resultSet = statement.executeQuery();
89
90 return StreamSupport.stream(new Spliterators.AbstractSpliterator<>(Long.MAX_VALUE, Spliterator.ORDERED) {
91 @Override
92 public boolean tryAdvance(final Consumer<? super T> consumer) {
93 try {
94 if (!resultSet.next()) {
95 return false;
96 }
97 consumer.accept(mapper.apply(resultSet));
98 return true;
99 } catch (SQLException e) {
100 logger.warn("Failed to read from database result", e);
101 throw new RuntimeException(e);
102 }
103 }
104 }, false);
105 }
106
107 public interface ResultSetMapper<T> {
108
109 T apply(ResultSet resultSet) throws SQLException;
110 }
111 }