diff --git a/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java b/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java index 729ba671097e9530ed33b85d86a5207a8c7aac62..15fb7e524bd529f40f840e881bfc6d4cdafb30f4 100644 --- a/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java +++ b/datastore/src/main/java/net/jami/datastore/dao/ContactDao.java @@ -1,25 +1,26 @@ /* -* Copyright (C) 2020 by Savoir-faire Linux -* Authors: William Enright <william.enright@savoirfairelinux.com> -* Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com> -* Johnny Flores <johnny.flores@savoirfairelinux.com> -* Mohammed Raza <mohammed.raza@savoirfairelinux.com> -* Felix Sidokhine <felix.sidokhine@savoirfairelinux.com> -* -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU 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 General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ + * Copyright (C) 2020 by Savoir-faire Linux + * Authors: William Enright <william.enright@savoirfairelinux.com> + * Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com> + * Johnny Flores <johnny.flores@savoirfairelinux.com> + * Mohammed Raza <mohammed.raza@savoirfairelinux.com> + * Felix Sidokhine <felix.sidokhine@savoirfairelinux.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + package net.jami.datastore.dao; import lombok.extern.slf4j.Slf4j; @@ -29,6 +30,7 @@ import net.jami.jams.common.objects.contacts.Contact; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.util.List; @Slf4j public class ContactDao extends AbstractDao<Contact> { @@ -41,35 +43,57 @@ public class ContactDao extends AbstractDao<Contact> { String createTable = "CREATE TABLE contacts (" + "owner varchar(255), " + "uri varchar(255)," + - "displayName varchar(255),"+ + "displayName varchar(255)," + + "`timestamp` bigint," + + "status int," + "PRIMARY KEY (owner,uri))"; PreparedStatement ps = connection.getConnection().prepareStatement(createTable); ps.execute(); - } - catch (SQLException e){ + } catch (SQLException e) { log.error("Could not create the contacts table with error " + e.getMessage()); - } - finally { + } finally { DataStore.connectionPool.returnConnection(connection); } } + //Not used because the strategy here is different. @Override public boolean storeObject(Contact object) { SQLConnection connection = DataStore.connectionPool.getConnection(); - try{ - PreparedStatement ps = connection.getConnection().prepareStatement("INSERT INTO contacts " + - "(owner, uri, displayName) " + - "VALUES " + - "(?, ?, ?)"); - ps = object.getInsert(ps); - return ps.executeUpdate() != 0; - } - catch (Exception e){ - log.error("An error has occurred while trying to store a user: " + e.toString()); + try { + String insert = "INSERT INTO contacts (owner, uri, displayName, `timestamp`, status) VALUES " + + "(?, ?, ?, ?, ?)"; + PreparedStatement ps = connection.getConnection().prepareStatement(insert); + object.getInsert(ps); + ps.executeQuery(); + return true; + } catch (Exception e) { + log.error("Could not update contacts!"); return false; + } finally { + DataStore.connectionPool.returnConnection(connection); } - finally { + } + + public boolean storeContactList(List<Contact> contactList) { + SQLConnection connection = DataStore.connectionPool.getConnection(); + try { + String delete = "DELETE FROM contacts WHERE owner = ?"; + PreparedStatement ps = connection.getConnection().prepareStatement(delete); + ps.setString(1, contactList.get(0).getOwner()); + ps.executeQuery(); + String insert = "INSERT INTO contacts (owner, uri, displayName, `timestamp`, status) VALUES " + + "(?, ?, ?, ?, ?)"; + for (Contact contact : contactList) { + ps = connection.getConnection().prepareStatement(insert); + contact.getInsert(ps); + ps.executeQuery(); + } + return true; + } catch (Exception e) { + log.error("Could not update contacts!"); + return false; + } finally { DataStore.connectionPool.returnConnection(connection); } } diff --git a/jams-common/src/main/java/net/jami/jams/common/objects/contacts/Contact.java b/jams-common/src/main/java/net/jami/jams/common/objects/contacts/Contact.java index dfcf11b391b0b0dcc43ead99a63f88183f40affa..04da47e1231be91a5b1fb99a778aea0930ff7053 100644 --- a/jams-common/src/main/java/net/jami/jams/common/objects/contacts/Contact.java +++ b/jams-common/src/main/java/net/jami/jams/common/objects/contacts/Contact.java @@ -1,28 +1,30 @@ /* -* Copyright (C) 2020 by Savoir-faire Linux -* Authors: William Enright <william.enright@savoirfairelinux.com> -* Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com> -* Johnny Flores <johnny.flores@savoirfairelinux.com> -* Mohammed Raza <mohammed.raza@savoirfairelinux.com> -* Felix Sidokhine <felix.sidokhine@savoirfairelinux.com> -* -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU 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 General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ + * Copyright (C) 2020 by Savoir-faire Linux + * Authors: William Enright <william.enright@savoirfairelinux.com> + * Ndeye Anna Ndiaye <anna.ndiaye@savoirfairelinux.com> + * Johnny Flores <johnny.flores@savoirfairelinux.com> + * Mohammed Raza <mohammed.raza@savoirfairelinux.com> + * Felix Sidokhine <felix.sidokhine@savoirfairelinux.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + package net.jami.jams.common.objects.contacts; import com.jsoniter.annotation.JsonIgnore; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -34,24 +36,32 @@ import java.sql.ResultSet; @Getter @Setter @NoArgsConstructor +@EqualsAndHashCode public class Contact implements DatabaseObject { @JsonIgnore //Ignore the owner because he is irrelevant. private String owner; private String uri; private String displayName; + private Long timestamp; + private Character status; //A = added, D = deleted. public Contact(ResultSet rs) throws Exception { this.owner = rs.getString("owner"); this.uri = rs.getString("uri"); this.displayName = rs.getString("displayName"); + this.timestamp = rs.getLong("timestamp"); + this.status = (char) rs.getInt("status"); } @Override public PreparedStatement getInsert(PreparedStatement ps) throws Exception { - ps.setString(1,owner); - ps.setString(2,uri); - ps.setString(3,displayName); + ps.setString(1, owner); + ps.setString(2, uri); + if(displayName != null) ps.setString(3, displayName); + else ps.setString(3, ""); + ps.setLong(4,timestamp); + ps.setInt(5,status); return ps; } diff --git a/jams-common/src/main/java/net/jami/jams/common/serialization/JsoniterRegistry.java b/jams-common/src/main/java/net/jami/jams/common/serialization/JsoniterRegistry.java index 46c0bb828afc0f185c464ed887a4086a5e2670e4..f3191945f184447ce051aa678db7356ac02e8a0e 100644 --- a/jams-common/src/main/java/net/jami/jams/common/serialization/JsoniterRegistry.java +++ b/jams-common/src/main/java/net/jami/jams/common/serialization/JsoniterRegistry.java @@ -27,11 +27,13 @@ import com.jsoniter.output.EncodingMode; import com.jsoniter.output.JsonStream; import com.jsoniter.spi.DecodingMode; import com.jsoniter.spi.JsoniterSpi; +import net.jami.jams.common.objects.contacts.Contact; import net.jami.jams.common.serialization.decoders.CSRDecoder; import net.jami.jams.common.serialization.decoders.PrivateKeyDecoder; import net.jami.jams.common.serialization.decoders.X509CertificateDecoder; import net.jami.jams.common.serialization.encoders.PrivateKeyEncoder; import net.jami.jams.common.serialization.encoders.X509CertificateEncoder; +import net.jami.jams.common.serialization.serializers.ContactCodec; import org.bouncycastle.pkcs.PKCS10CertificationRequest; import java.security.PrivateKey; @@ -47,6 +49,8 @@ public class JsoniterRegistry { JsoniterSpi.registerTypeEncoder(X509Certificate.class,new X509CertificateEncoder()); JsoniterSpi.registerTypeEncoder(PrivateKey.class,new PrivateKeyEncoder()); JsoniterSpi.registerTypeDecoder(PKCS10CertificationRequest.class,new CSRDecoder()); + JsoniterSpi.registerTypeEncoder(Contact.class,new ContactCodec()); + JsoniterSpi.registerTypeDecoder(Contact.class,new ContactCodec()); } diff --git a/jams-common/src/main/java/net/jami/jams/common/serialization/serializers/ContactCodec.java b/jams-common/src/main/java/net/jami/jams/common/serialization/serializers/ContactCodec.java new file mode 100644 index 0000000000000000000000000000000000000000..f2ee78972523e70dec65c498f24e218a7d7aa46a --- /dev/null +++ b/jams-common/src/main/java/net/jami/jams/common/serialization/serializers/ContactCodec.java @@ -0,0 +1,42 @@ +package net.jami.jams.common.serialization.serializers; + +import com.jsoniter.JsonIterator; +import com.jsoniter.any.Any; +import com.jsoniter.output.JsonStream; +import com.jsoniter.spi.Decoder; +import com.jsoniter.spi.Encoder; +import net.jami.jams.common.objects.contacts.Contact; + +import java.io.IOException; + +public class ContactCodec implements Encoder, Decoder { + + @Override + public Object decode(JsonIterator jsonIterator) throws IOException { + Any input = jsonIterator.readAny(); + Contact contact = new Contact(); + contact.setUri(input.get("uri").toString()); + if(!input.get("added").toString().isBlank()){ + contact.setStatus('A'); + contact.setTimestamp(input.get("added").toLong()); + } + else{ + contact.setStatus('D'); + contact.setTimestamp(input.get("removed").toLong()); + } + return contact; + } + + @Override + public void encode(Object o, JsonStream jsonStream) throws IOException { + Contact ct = (Contact) o; + StringBuilder sb = new StringBuilder(); + sb.append("{\"uri\":\"").append(ct.getUri()).append("\","); + switch (ct.getStatus()){ + case 'A': sb.append("\"added\":").append(ct.getTimestamp()); break; + case 'D': sb.append("\"removed\":").append(ct.getTimestamp()); break; + } + sb.append("}"); + jsonStream.write(sb.toString().getBytes()); + } +} diff --git a/jams-common/src/main/java/net/jami/jams/common/utils/ContactMerger.java b/jams-common/src/main/java/net/jami/jams/common/utils/ContactMerger.java new file mode 100644 index 0000000000000000000000000000000000000000..f73f276cf6e4dd1db441dc4674c3820de4556082 --- /dev/null +++ b/jams-common/src/main/java/net/jami/jams/common/utils/ContactMerger.java @@ -0,0 +1,38 @@ +package net.jami.jams.common.utils; + +import net.jami.jams.common.objects.contacts.Contact; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + +public class ContactMerger { + + public static List<Contact> mergeContacts(List<Contact> remote, List<Contact> local){ + //uri - [remote,local] + List<Contact> output = new ArrayList<>(); + final HashMap<String,Contact[]> contactMap = new HashMap<>(); + remote.sort(Comparator.comparingLong(Contact::getTimestamp)); + remote.forEach(contact -> { + contactMap.putIfAbsent(contact.getUri(),new Contact[]{null,null}); + contactMap.get(contact.getUri())[0] = contact; + }); + local.forEach(contact -> { + contactMap.putIfAbsent(contact.getUri(),new Contact[]{null,null}); + contactMap.get(contact.getUri())[1] = contact; + }); + contactMap.forEach((k,v) -> { + if(v[0] == null) output.add(v[1]); + else if(v[1] == null) output.add(v[0]); + else { + //Compare by date an choose the proper one + if(v[0].getTimestamp() > v[1].getTimestamp()) output.add(v[0]); + else output.add(v[1]); + } + }); + return output; + } + + +} diff --git a/jams-common/src/test/java/net/jami/jams/common/objects/contacts/ContactTest.java b/jams-common/src/test/java/net/jami/jams/common/objects/contacts/ContactTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7ec4acaee20ec5c95da379087b5db1042fa718d3 --- /dev/null +++ b/jams-common/src/test/java/net/jami/jams/common/objects/contacts/ContactTest.java @@ -0,0 +1,76 @@ +package net.jami.jams.common.objects.contacts; + +import com.jsoniter.JsonIterator; +import com.jsoniter.output.JsonStream; +import com.jsoniter.spi.JsoniterSpi; +import net.jami.jams.common.serialization.serializers.ContactCodec; +import net.jami.jams.common.utils.ContactMerger; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class ContactTest { + + @BeforeAll + public static void init(){ + JsoniterSpi.registerTypeDecoder(Contact.class,new ContactCodec()); + JsoniterSpi.registerTypeEncoder(Contact.class,new ContactCodec()); + } + + @Test + public void deserialize(){ + String str = "[{\"uri\":\"tcp://def@local\",\"added\":1594742298377},{\"uri\":\"tcp://abc@19293.com\",\"removed\":1594742298377}]"; + Contact[] contacts = JsonIterator.deserialize(str,Contact[].class); + Assertions.assertEquals(2,contacts.length); + } + + @Test + public void serialize(){ + Contact contact1 = new Contact(); + contact1.setOwner("fsidokhine"); + contact1.setStatus('A'); + contact1.setTimestamp(System.currentTimeMillis()); + contact1.setUri("tcp://def@local"); + Contact contact2 = new Contact(); + contact2.setOwner("fsidokhine"); + contact2.setStatus('D'); + contact2.setTimestamp(System.currentTimeMillis()); + contact2.setUri("tcp://abc@19293.com"); + ArrayList<Contact> lst = new ArrayList<>(); + lst.add(contact1); + lst.add(contact2); + String str = JsonStream.serialize(lst); + Assertions.assertNotNull(str); + } + + @Test + public void mergeTest(){ + Contact contact1 = new Contact(); + contact1.setOwner("fsidokhine"); + contact1.setStatus('A'); + contact1.setTimestamp(System.currentTimeMillis()); + contact1.setUri("tcp://def@local"); + Contact contact2 = new Contact(); + contact2.setOwner("fsidokhine"); + contact2.setStatus('D'); + contact2.setTimestamp(System.currentTimeMillis()); + contact2.setUri("tcp://abc@19293.com"); + ArrayList<Contact> lst = new ArrayList<>(); + lst.add(contact1); + lst.add(contact2); + Contact contact3 = new Contact(); + contact3.setOwner("fsidokhine"); + contact3.setStatus('A'); + contact3.setTimestamp(System.currentTimeMillis() + 10000); + contact3.setUri("tcp://abc@19293.com"); + ArrayList<Contact> lst2 = new ArrayList<>(); + lst2.add(contact3); + List<Contact> out = ContactMerger.mergeContacts(lst,lst2); + Assertions.assertEquals(2,out.size()); + } +} \ No newline at end of file diff --git a/jams-launcher/src/main/java/launcher/AppStarter.java b/jams-launcher/src/main/java/launcher/AppStarter.java index da0e68e29528f017c185ae3b5db1a78055ecf1f5..e56560b2e1479d5bfb6a474bb56c74dea86fa8e3 100644 --- a/jams-launcher/src/main/java/launcher/AppStarter.java +++ b/jams-launcher/src/main/java/launcher/AppStarter.java @@ -87,7 +87,7 @@ public class AppStarter extends Thread { public AppStarter(String[] args) { parentArgs = args; try { - jamsProcessId = startAccountManagementServer(args); + startAccountManagementServer(args); setupZmqBridge(); Runtime.getRuntime().addShutdownHook(new Thread(() -> { log.info("Shutting down..."); @@ -108,6 +108,7 @@ public class AppStarter extends Thread { //and run the good old routine @Override public void run() { + //TODO: Hack this a bit to get it to work better - passing arguments damnit. while (true) { try { if (doUpdate.get()) { @@ -115,7 +116,7 @@ public class AppStarter extends Thread { ProcessHandle.of(jamsProcessId).get().destroyForcibly(); // transfer newly downloaded files to the right folder. doUpdate.set(false); - //Unpack the update. + //Upack the update. unpackUpdate(); // Restart the main JAR and set the processId to it. jamsProcessId = startAccountManagementServer(parentArgs); @@ -133,6 +134,7 @@ public class AppStarter extends Thread { public static long startAccountManagementServer(String[] parentArgs) throws IOException { ProcessBuilder pb = null; + Process p; switch (parentArgs.length) { case 1: pb = new ProcessBuilder("java", "-jar", "jams-server.jar", parentArgs[0]); @@ -147,7 +149,7 @@ public class AppStarter extends Thread { assert pb != null; pb.directory(new File(System.getProperty("user.dir"))); pb.inheritIO(); - Process p = pb.start(); + p = pb.start(); return p.pid(); } } \ No newline at end of file diff --git a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/contacts/ContactServlet.java b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/contacts/ContactServlet.java index 0f176bd3461bde040455603e8d220f1eb0f56057..d521a2e7bba27d714b16b7e9c79881b90b8c84e4 100644 --- a/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/contacts/ContactServlet.java +++ b/jams-server/src/main/java/net/jami/jams/server/servlets/api/auth/contacts/ContactServlet.java @@ -33,8 +33,11 @@ import net.jami.jams.common.dao.StatementElement; import net.jami.jams.common.dao.StatementList; import net.jami.jams.common.objects.contacts.Contact; import net.jami.jams.common.serialization.tomcat.TomcatCustomErrorHandler; +import net.jami.jams.common.utils.ContactMerger; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static net.jami.jams.server.Server.dataStore; @@ -42,6 +45,7 @@ import static net.jami.jams.server.Server.dataStore; @WebServlet("/api/auth/contacts") public class ContactServlet extends HttpServlet { + /** * @apiVersion 1.0.0 * @api {get} /api/auth/contacts View contacts @@ -52,8 +56,13 @@ public class ContactServlet extends HttpServlet { * @apiSuccessExample {json} Success-Response: * [{ * "uri": "jami://7e3ab29383", - * "displayName": "John Doe" - * }] + * "added": 18272662662 + * }, + * { + * "uri": "jami://7e3ab29383", + * "removed": 12387873 + * }, + * ] */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { @@ -63,6 +72,7 @@ public class ContactServlet extends HttpServlet { resp.getOutputStream().write(JsonStream.serialize(contactList).getBytes()); } + /** * @apiVersion 1.0.0 * @api {put} /api/auth/contacts Add a contact @@ -72,8 +82,7 @@ public class ContactServlet extends HttpServlet { * @apiParam {body} Contact JSON representation of the contact object * @apiParamExample {json} Request-Example: * { - * "uri": "jami://7e3ab29383", - * "displayName": "John Doe" + * "uri": "jami://7e3ab29383" * } * * @apiSuccess (200) {null} null successfully added contact @@ -82,8 +91,17 @@ public class ContactServlet extends HttpServlet { @Override protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Contact contact = JsonIterator.deserialize(req.getInputStream().readAllBytes(),Contact.class); + //TODO: Replace with mergetool. + contact.setTimestamp(System.currentTimeMillis()); + contact.setStatus('A'); contact.setOwner(req.getAttribute("username").toString()); - if(dataStore.getContactDao().storeObject(contact)) resp.setStatus(200); + StatementList statementList = new StatementList(); + statementList.addStatement(new StatementElement("owner","=",req.getAttribute("username").toString(),"")); + List<Contact> localList = dataStore.getContactDao().getObjects(statementList); + List<Contact> remoteList = new ArrayList<>(); + remoteList.add(contact); + List<Contact> result = ContactMerger.mergeContacts(localList,remoteList); + if(dataStore.getContactDao().storeContactList(result)) resp.setStatus(200); else TomcatCustomErrorHandler.sendCustomError(resp,500,"could not store a contact due to server-side error"); } @@ -103,7 +121,42 @@ public class ContactServlet extends HttpServlet { StatementList statementList = new StatementList(); statementList.addStatement(new StatementElement("owner","=",req.getAttribute("username").toString(),"AND")); statementList.addStatement(new StatementElement("uri","=",req.getParameter("uri"),"")); - if(dataStore.getContactDao().deleteObject(statementList)) resp.setStatus(200); + List<Contact> remoteList = dataStore.getContactDao().getObjects(statementList); + remoteList.get(0).setStatus('D'); + remoteList.get(0).setTimestamp(System.currentTimeMillis()); + statementList = new StatementList(); + statementList.addStatement(new StatementElement("owner","=",req.getAttribute("username").toString(),"AND")); + List<Contact> localList = dataStore.getContactDao().getObjects(statementList); + List<Contact> result = ContactMerger.mergeContacts(localList,remoteList); + if(dataStore.getContactDao().storeContactList(result)) resp.setStatus(200); else TomcatCustomErrorHandler.sendCustomError(resp,500,"could not delete a contact due to server-side error"); } + + + /** + * @apiVersion 1.0.0 + * @api {post} /api/auth/contacts Add a contact + * @apiName putContact + * @apiGroup Contacts + * + * @apiParam {body} Contact JSON representation of the contact object + * @apiParamExample {json} Request-Example: + *[ + * {"uri":"tcp://def@local","added":1594742298377}, + * {"uri":"tcp://abc@19293.com","removed":1594742298377} + * ] + * + * @apiSuccess (200) {json} Contact[] successfully added contact + * @apiError (500) {null} null contact could not be successfully added + */ + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + StatementList statementList = new StatementList(); + statementList.addStatement(new StatementElement("owner","=",req.getAttribute("username").toString(),"")); + List<Contact> localList = dataStore.getContactDao().getObjects(statementList); + List<Contact> remoteList = Arrays.asList(JsonIterator.deserialize(req.getInputStream().readAllBytes(),Contact[].class)); + List<Contact> result = ContactMerger.mergeContacts(localList,remoteList); + if(!dataStore.getContactDao().storeContactList(result)) TomcatCustomErrorHandler.sendCustomError(resp,500,"Could not store contacts!"); + resp.getOutputStream().write(JsonStream.serialize(result).getBytes()); + } } diff --git a/ldap-connector/src/main/java/net/jami/jams/ldap/connector/service/UserProfileService.java b/ldap-connector/src/main/java/net/jami/jams/ldap/connector/service/UserProfileService.java index e8178efa0e8d3e436db4f55a26de17d3d8c46bf5..1fe4a9d5cb105a3ccd0297bf72f784b407ad4a29 100644 --- a/ldap-connector/src/main/java/net/jami/jams/ldap/connector/service/UserProfileService.java +++ b/ldap-connector/src/main/java/net/jami/jams/ldap/connector/service/UserProfileService.java @@ -51,7 +51,7 @@ public class UserProfileService { UserProfile[] profiles = null; Connection connection = null; try { - queryString = URLEncoder.encode(queryString,StandardCharsets.UTF_8).replace("%","\\"); + queryString = queryString.replaceAll("[^\\x00-\\x7F]","*"); connection = connectionFactory.getConnection(); try { connection.open(); @@ -84,7 +84,7 @@ public class UserProfileService { public static SearchRequest buildRequest(String queryString, String field) { if (!queryString.startsWith("*")) - queryString = queryString.concat("*"); + queryString = "*".concat(queryString).concat("*"); if(field.equals("LOGON_NAME")) { return SearchRequest.builder()