diff --git a/docs/backends/rest.md b/docs/backends/rest.md index 600f0c3..e3c0eec 100644 --- a/docs/backends/rest.md +++ b/docs/backends/rest.md @@ -93,8 +93,8 @@ Encoding: JSON UTF-8 ``` #### Response Body -`lookup.uid` contains the Matrix ID localpart of the user - +If a match was found: +- `lookup.id.type` supported values: `localpart`, `mxid` ``` { "lookup": { @@ -108,6 +108,11 @@ Encoding: JSON UTF-8 } ``` +If no match was found: +``` +{} +``` + #### Bulk Configured with `rest.endpoints.identity.bulk` @@ -131,6 +136,8 @@ Encoding: JSON UTF-8 ``` #### Response Body +For all entries where a match was found: +- `lookup[].id.type` supported values: `localpart`, `mxid` ``` { "lookup": [ @@ -153,3 +160,10 @@ Encoding: JSON UTF-8 ] } ``` + +If no match was found: +``` +{ + "lookup": [] +} +``` \ No newline at end of file diff --git a/src/main/groovy/io/kamax/mxisd/auth/AuthManager.java b/src/main/groovy/io/kamax/mxisd/auth/AuthManager.java index aad2cbd..8ad8edf 100644 --- a/src/main/groovy/io/kamax/mxisd/auth/AuthManager.java +++ b/src/main/groovy/io/kamax/mxisd/auth/AuthManager.java @@ -21,6 +21,7 @@ package io.kamax.mxisd.auth; import io.kamax.matrix.MatrixID; +import io.kamax.matrix._MatrixID; import io.kamax.mxisd.ThreePid; import io.kamax.mxisd.UserIdType; import io.kamax.mxisd.auth.provider.AuthenticatorProvider; @@ -51,12 +52,13 @@ public class AuthManager { private InvitationManager invMgr; public UserAuthResult authenticate(String id, String password) { + _MatrixID mxid = new MatrixID(id); for (AuthenticatorProvider provider : providers) { if (!provider.isEnabled()) { continue; } - BackendAuthResult result = provider.authenticate(id, password); + BackendAuthResult result = provider.authenticate(mxid, password); if (result.isSuccess()) { String mxId; diff --git a/src/main/groovy/io/kamax/mxisd/auth/provider/AuthenticatorProvider.java b/src/main/groovy/io/kamax/mxisd/auth/provider/AuthenticatorProvider.java index 6103f36..c3c58bc 100644 --- a/src/main/groovy/io/kamax/mxisd/auth/provider/AuthenticatorProvider.java +++ b/src/main/groovy/io/kamax/mxisd/auth/provider/AuthenticatorProvider.java @@ -20,10 +20,12 @@ package io.kamax.mxisd.auth.provider; +import io.kamax.matrix._MatrixID; + public interface AuthenticatorProvider { boolean isEnabled(); - BackendAuthResult authenticate(String id, String password); + BackendAuthResult authenticate(_MatrixID mxid, String password); } diff --git a/src/main/groovy/io/kamax/mxisd/backend/firebase/GoogleFirebaseAuthenticator.groovy b/src/main/groovy/io/kamax/mxisd/backend/firebase/GoogleFirebaseAuthenticator.groovy index 7139f2a..4533f3a 100644 --- a/src/main/groovy/io/kamax/mxisd/backend/firebase/GoogleFirebaseAuthenticator.groovy +++ b/src/main/groovy/io/kamax/mxisd/backend/firebase/GoogleFirebaseAuthenticator.groovy @@ -27,6 +27,7 @@ import com.google.firebase.internal.NonNull import com.google.firebase.tasks.OnFailureListener import com.google.firebase.tasks.OnSuccessListener import io.kamax.matrix.ThreePidMedium +import io.kamax.matrix._MatrixID import io.kamax.mxisd.ThreePid import io.kamax.mxisd.UserIdType import io.kamax.mxisd.auth.provider.AuthenticatorProvider @@ -37,7 +38,6 @@ import org.slf4j.LoggerFactory import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit -import java.util.regex.Matcher import java.util.regex.Pattern public class GoogleFirebaseAuthenticator implements AuthenticatorProvider { @@ -110,17 +110,12 @@ public class GoogleFirebaseAuthenticator implements AuthenticatorProvider { } @Override - public BackendAuthResult authenticate(String id, String password) { + public BackendAuthResult authenticate(_MatrixID mxid, String password) { if (!isEnabled()) { throw new IllegalStateException(); } - log.info("Trying to authenticate {}", id); - Matcher m = matrixIdLaxPattern.matcher(id); - if (!m.matches()) { - log.warn("Could not validate {} as a Matrix ID", id); - BackendAuthResult.failure(); - } + log.info("Trying to authenticate {}", mxid); BackendAuthResult result = BackendAuthResult.failure(); @@ -136,9 +131,9 @@ public class GoogleFirebaseAuthenticator implements AuthenticatorProvider { return; } - result = BackendAuthResult.success(id, UserIdType.MatrixID, token.getName()); - log.info("{} was successfully authenticated", id); - log.info("Fetching profile for {}", id); + result = BackendAuthResult.success(mxid.getId(), UserIdType.MatrixID, token.getName()); + log.info("{} was successfully authenticated", mxid); + log.info("Fetching profile for {}", mxid); CountDownLatch userRecordLatch = new CountDownLatch(1); fbAuth.getUser(token.getUid()).addOnSuccessListener(new OnSuccessListener() { @Override @@ -160,7 +155,7 @@ public class GoogleFirebaseAuthenticator implements AuthenticatorProvider { @Override void onFailure(@NonNull Exception e) { try { - log.warn("Unable to fetch Firebase user profile for {}", id); + log.warn("Unable to fetch Firebase user profile for {}", mxid); result = BackendAuthResult.failure(); } finally { userRecordLatch.countDown(); @@ -178,7 +173,7 @@ public class GoogleFirebaseAuthenticator implements AuthenticatorProvider { void onFailure(@NonNull Exception e) { try { if (e instanceof IllegalArgumentException) { - log.info("Failure to authenticate {}: invalid firebase token", id); + log.info("Failure to authenticate {}: invalid firebase token", mxid); } else { log.info("Failure to authenticate {}: {}", id, e.getMessage(), e); log.info("Exception", e); diff --git a/src/main/groovy/io/kamax/mxisd/backend/ldap/LdapAuthProvider.java b/src/main/groovy/io/kamax/mxisd/backend/ldap/LdapAuthProvider.java index 970b379..6162941 100644 --- a/src/main/groovy/io/kamax/mxisd/backend/ldap/LdapAuthProvider.java +++ b/src/main/groovy/io/kamax/mxisd/backend/ldap/LdapAuthProvider.java @@ -20,7 +20,7 @@ package io.kamax.mxisd.backend.ldap; -import io.kamax.matrix.MatrixID; +import io.kamax.matrix._MatrixID; import io.kamax.mxisd.UserIdType; import io.kamax.mxisd.auth.provider.AuthenticatorProvider; import io.kamax.mxisd.auth.provider.BackendAuthResult; @@ -54,16 +54,15 @@ public class LdapAuthProvider extends LdapGenericBackend implements Authenticato } @Override - public BackendAuthResult authenticate(String id, String password) { - log.info("Performing auth for {}", id); + public BackendAuthResult authenticate(_MatrixID mxid, String password) { + log.info("Performing auth for {}", mxid); LdapConnection conn = getConn(); try { bind(conn); String uidType = getCfg().getAttribute().getUid().getType(); - MatrixID mxIdExt = new MatrixID(id); - String userFilterValue = StringUtils.equals(LdapThreePidProvider.UID, uidType) ? mxIdExt.getLocalPart() : mxIdExt.getId(); + String userFilterValue = StringUtils.equals(LdapThreePidProvider.UID, uidType) ? mxid.getLocalPart() : mxid.getId(); String userFilter = "(" + getCfg().getAttribute().getUid().getValue() + "=" + userFilterValue + ")"; EntryCursor cursor = conn.search(getCfg().getConn().getBaseDn(), userFilter, SearchScope.SUBTREE, getUidAttribute(), getCfg().getAttribute().getName()); try { @@ -99,15 +98,15 @@ public class LdapAuthProvider extends LdapGenericBackend implements Authenticato log.info("DN {} is a valid match", dn); // TODO should we canonicalize the MXID? - return BackendAuthResult.success(mxIdExt.getId(), UserIdType.MatrixID, name); + return BackendAuthResult.success(mxid.getId(), UserIdType.MatrixID, name); } } catch (CursorLdapReferralException e) { - log.warn("Entity for {} is only available via referral, skipping", mxIdExt); + log.warn("Entity for {} is only available via referral, skipping", mxid); } finally { cursor.close(); } - log.info("No match were found for {}", id); + log.info("No match were found for {}", mxid); return BackendAuthResult.failure(); } catch (LdapException | IOException | CursorException e) { throw new RuntimeException(e); diff --git a/src/main/groovy/io/kamax/mxisd/backend/rest/LookupBulkResponseJson.java b/src/main/groovy/io/kamax/mxisd/backend/rest/LookupBulkResponseJson.java new file mode 100644 index 0000000..fb0797c --- /dev/null +++ b/src/main/groovy/io/kamax/mxisd/backend/rest/LookupBulkResponseJson.java @@ -0,0 +1,34 @@ +/* + * mxisd - Matrix Identity Server Daemon + * Copyright (C) 2017 Maxime Dor + * + * https://max.kamax.io/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package io.kamax.mxisd.backend.rest; + +import java.util.ArrayList; +import java.util.List; + +public class LookupBulkResponseJson { + + private List lookup = new ArrayList<>(); + + public List getLookup() { + return lookup; + } + +} diff --git a/src/main/groovy/io/kamax/mxisd/backend/rest/LookupSingleRequestJson.java b/src/main/groovy/io/kamax/mxisd/backend/rest/LookupSingleRequestJson.java new file mode 100644 index 0000000..618f5b3 --- /dev/null +++ b/src/main/groovy/io/kamax/mxisd/backend/rest/LookupSingleRequestJson.java @@ -0,0 +1,40 @@ +/* + * mxisd - Matrix Identity Server Daemon + * Copyright (C) 2017 Maxime Dor + * + * https://max.kamax.io/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package io.kamax.mxisd.backend.rest; + +public class LookupSingleRequestJson { + + private String medium; + private String address; + + public LookupSingleRequestJson(String medium, String address) { + this.medium = medium; + this.address = address; + } + + public String getMedium() { + return medium; + } + + public String getAddress() { + return address; + } +} diff --git a/src/main/groovy/io/kamax/mxisd/backend/rest/LookupSingleResponseJson.java b/src/main/groovy/io/kamax/mxisd/backend/rest/LookupSingleResponseJson.java new file mode 100644 index 0000000..7bc9246 --- /dev/null +++ b/src/main/groovy/io/kamax/mxisd/backend/rest/LookupSingleResponseJson.java @@ -0,0 +1,43 @@ +/* + * mxisd - Matrix Identity Server Daemon + * Copyright (C) 2017 Maxime Dor + * + * https://max.kamax.io/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package io.kamax.mxisd.backend.rest; + +import io.kamax.mxisd.UserID; + +public class LookupSingleResponseJson { + + private String medium; + private String address; + private UserID id; + + public String getMedium() { + return medium; + } + + public String getAddress() { + return address; + } + + public UserID getId() { + return id; + } + +} diff --git a/src/main/groovy/io/kamax/mxisd/backend/rest/RestAuthProvider.java b/src/main/groovy/io/kamax/mxisd/backend/rest/RestAuthProvider.java index 8a07c4b..0191c2e 100644 --- a/src/main/groovy/io/kamax/mxisd/backend/rest/RestAuthProvider.java +++ b/src/main/groovy/io/kamax/mxisd/backend/rest/RestAuthProvider.java @@ -20,40 +20,24 @@ package io.kamax.mxisd.backend.rest; -import com.google.gson.FieldNamingPolicy; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import io.kamax.matrix.MatrixID; import io.kamax.matrix._MatrixID; import io.kamax.mxisd.auth.provider.AuthenticatorProvider; import io.kamax.mxisd.auth.provider.BackendAuthResult; import io.kamax.mxisd.config.rest.RestBackendConfig; -import io.kamax.mxisd.util.GsonParser; import io.kamax.mxisd.util.RestClientUtils; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.IOException; @Component -public class RestAuthProvider implements AuthenticatorProvider { - - private RestBackendConfig cfg; - private Gson gson; - private GsonParser parser; - private CloseableHttpClient client; +public class RestAuthProvider extends RestProvider implements AuthenticatorProvider { @Autowired public RestAuthProvider(RestBackendConfig cfg) { - this.cfg = cfg; - - client = HttpClients.createDefault(); - gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); - parser = new GsonParser(gson); + super(cfg); } @Override @@ -62,10 +46,9 @@ public class RestAuthProvider implements AuthenticatorProvider { } @Override - public BackendAuthResult authenticate(String id, String password) { - _MatrixID mxid = new MatrixID(id); + public BackendAuthResult authenticate(_MatrixID mxid, String password) { RestAuthRequestJson auth = new RestAuthRequestJson(); - auth.setMxid(id); + auth.setMxid(mxid.getId()); auth.setLocalpart(mxid.getLocalPart()); auth.setDomain(mxid.getDomain()); auth.setPassword(password); diff --git a/src/main/groovy/io/kamax/mxisd/backend/rest/RestProvider.java b/src/main/groovy/io/kamax/mxisd/backend/rest/RestProvider.java new file mode 100644 index 0000000..1c34438 --- /dev/null +++ b/src/main/groovy/io/kamax/mxisd/backend/rest/RestProvider.java @@ -0,0 +1,46 @@ +/* + * mxisd - Matrix Identity Server Daemon + * Copyright (C) 2017 Maxime Dor + * + * https://max.kamax.io/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package io.kamax.mxisd.backend.rest; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import io.kamax.mxisd.config.rest.RestBackendConfig; +import io.kamax.mxisd.util.GsonParser; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; + +public class RestProvider { + + protected RestBackendConfig cfg; + protected Gson gson; + protected GsonParser parser; + protected CloseableHttpClient client; + + public RestProvider(RestBackendConfig cfg) { + this.cfg = cfg; + + client = HttpClients.createDefault(); + gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create(); + parser = new GsonParser(gson); + } + +} diff --git a/src/main/groovy/io/kamax/mxisd/backend/rest/RestThreePidProvider.java b/src/main/groovy/io/kamax/mxisd/backend/rest/RestThreePidProvider.java index 86d5c8f..c72e3c1 100644 --- a/src/main/groovy/io/kamax/mxisd/backend/rest/RestThreePidProvider.java +++ b/src/main/groovy/io/kamax/mxisd/backend/rest/RestThreePidProvider.java @@ -20,23 +20,47 @@ package io.kamax.mxisd.backend.rest; +import io.kamax.matrix.MatrixID; +import io.kamax.matrix._MatrixID; +import io.kamax.mxisd.UserID; +import io.kamax.mxisd.UserIdType; +import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.rest.RestBackendConfig; import io.kamax.mxisd.lookup.SingleLookupReply; import io.kamax.mxisd.lookup.SingleLookupRequest; import io.kamax.mxisd.lookup.ThreePidMapping; import io.kamax.mxisd.lookup.provider.IThreePidProvider; -import org.apache.commons.lang.NotImplementedException; +import io.kamax.mxisd.util.RestClientUtils; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpUriRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @Component -public class RestThreePidProvider implements IThreePidProvider { +public class RestThreePidProvider extends RestProvider implements IThreePidProvider { + + private MatrixConfig mxCfg; // FIXME should be done in the lookup manager @Autowired - private RestBackendConfig cfg; + public RestThreePidProvider(RestBackendConfig cfg, MatrixConfig mxCfg) { + super(cfg); + this.mxCfg = mxCfg; + } + + // TODO refactor in lookup manager with above FIXME + private _MatrixID getMxId(UserID id) { + if (UserIdType.Localpart.is(id.getType())) { + return new MatrixID(id.getValue()); + } else { + return new MatrixID(id.getValue(), mxCfg.getDomain()); + } + } @Override public boolean isEnabled() { @@ -53,14 +77,51 @@ public class RestThreePidProvider implements IThreePidProvider { return 20; } + // TODO refactor common code @Override public Optional find(SingleLookupRequest request) { - throw new NotImplementedException(); + HttpUriRequest req = RestClientUtils.post( + cfg.getEndpoints().getAuth(), + gson, + "lookup", + new LookupSingleRequestJson(request.getType(), request.getThreePid())); + + try (CloseableHttpResponse res = client.execute(req)) { + int status = res.getStatusLine().getStatusCode(); + if (status < 200 || status >= 300) { + return Optional.empty(); + } + + Optional responseOpt = parser.parseOptional(res, "lookup", LookupSingleResponseJson.class); + return responseOpt.map(lookupSingleResponseJson -> new SingleLookupReply(request, getMxId(lookupSingleResponseJson.getId()))); + } catch (IOException e) { + throw new RuntimeException(e); + } } + // TODO refactor common code @Override public List populate(List mappings) { - throw new NotImplementedException(); + List ioListRequest = mappings.stream() + .map(mapping -> new LookupSingleRequestJson(mapping.getMedium(), mapping.getValue())) + .collect(Collectors.toList()); + + HttpUriRequest req = RestClientUtils.post(cfg.getEndpoints().getAuth(), gson, "lookup", ioListRequest); + try (CloseableHttpResponse res = client.execute(req)) { + mappings = new ArrayList<>(); + + int status = res.getStatusLine().getStatusCode(); + if (status < 200 || status >= 300) { + return mappings; + } + + LookupBulkResponseJson listIo = parser.parse(res, LookupBulkResponseJson.class); + return listIo.getLookup().stream() + .map(io -> new ThreePidMapping(io.getMedium(), io.getAddress(), getMxId(io.getId()).getId())) + .collect(Collectors.toList()); + } catch (IOException e) { + throw new RuntimeException(e); + } } } diff --git a/src/main/groovy/io/kamax/mxisd/backend/sql/SqlAuthProvider.java b/src/main/groovy/io/kamax/mxisd/backend/sql/SqlAuthProvider.java index 17714ab..089f4ee 100644 --- a/src/main/groovy/io/kamax/mxisd/backend/sql/SqlAuthProvider.java +++ b/src/main/groovy/io/kamax/mxisd/backend/sql/SqlAuthProvider.java @@ -20,6 +20,7 @@ package io.kamax.mxisd.backend.sql; +import io.kamax.matrix._MatrixID; import io.kamax.mxisd.auth.provider.AuthenticatorProvider; import io.kamax.mxisd.auth.provider.BackendAuthResult; import io.kamax.mxisd.config.ServerConfig; @@ -50,7 +51,7 @@ public class SqlAuthProvider implements AuthenticatorProvider { } @Override - public BackendAuthResult authenticate(String id, String password) { + public BackendAuthResult authenticate(_MatrixID mxid, String password) { log.info("Performing dummy authentication try to force invite mapping refresh"); invMgr.lookupMappingsForInvites(); diff --git a/src/main/groovy/io/kamax/mxisd/exception/JsonMemberNotFoundException.java b/src/main/groovy/io/kamax/mxisd/exception/JsonMemberNotFoundException.java new file mode 100644 index 0000000..06a0885 --- /dev/null +++ b/src/main/groovy/io/kamax/mxisd/exception/JsonMemberNotFoundException.java @@ -0,0 +1,29 @@ +/* + * mxisd - Matrix Identity Server Daemon + * Copyright (C) 2017 Maxime Dor + * + * https://max.kamax.io/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package io.kamax.mxisd.exception; + +public class JsonMemberNotFoundException extends RuntimeException { + + public JsonMemberNotFoundException(String s) { + super(s); + } + +} diff --git a/src/main/groovy/io/kamax/mxisd/util/GsonParser.java b/src/main/groovy/io/kamax/mxisd/util/GsonParser.java index c528f5c..ec311c8 100644 --- a/src/main/groovy/io/kamax/mxisd/util/GsonParser.java +++ b/src/main/groovy/io/kamax/mxisd/util/GsonParser.java @@ -22,12 +22,14 @@ package io.kamax.mxisd.util; import com.google.gson.*; import io.kamax.mxisd.exception.InvalidResponseJsonException; +import io.kamax.mxisd.exception.JsonMemberNotFoundException; import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.util.Optional; public class GsonParser { @@ -42,18 +44,26 @@ public class GsonParser { this.gson = gson; } - public JsonObject parse(InputStream stream, String property) throws IOException { + public JsonObject parse(InputStream stream) throws IOException { JsonElement el = parser.parse(IOUtils.toString(stream, StandardCharsets.UTF_8)); if (!el.isJsonObject()) { throw new InvalidResponseJsonException("Response body is not a JSON object"); } - JsonObject obj = el.getAsJsonObject(); + return el.getAsJsonObject(); + } + + public T parse(HttpResponse res, Class type) throws IOException { + return gson.fromJson(parse(res.getEntity().getContent()), type); + } + + public JsonObject parse(InputStream stream, String property) throws IOException { + JsonObject obj = parse(stream); if (!obj.has(property)) { - throw new IOException("Member " + property + " does not exist"); + throw new JsonMemberNotFoundException("Member " + property + " does not exist"); } - el = obj.get(property); + JsonElement el = obj.get(property); if (!el.isJsonObject()) { throw new InvalidResponseJsonException("Member " + property + " is not a JSON object"); } @@ -70,4 +80,12 @@ public class GsonParser { return parse(res.getEntity().getContent(), memberName, type); } + public Optional parseOptional(HttpResponse res, String memberName, Class type) throws IOException { + try { + return Optional.of(parse(res.getEntity().getContent(), memberName, type)); + } catch (JsonMemberNotFoundException e) { + return Optional.empty(); + } + } + } diff --git a/src/main/groovy/io/kamax/mxisd/util/RestClientUtils.java b/src/main/groovy/io/kamax/mxisd/util/RestClientUtils.java index 23eaa2e..c521008 100644 --- a/src/main/groovy/io/kamax/mxisd/util/RestClientUtils.java +++ b/src/main/groovy/io/kamax/mxisd/util/RestClientUtils.java @@ -41,4 +41,8 @@ public class RestClientUtils { return post(url, JsonUtils.getObjAsString(gson, member, o)); } + public static HttpPost post(String url, Gson gson, Object o) { + return post(url, gson.toJson(o)); + } + }