Toutes les entreprises et les particuliers partagent un même besoin de conservation de leurs contacts à long terme.
Les entreprises confient souvent les leurs à un CRM ou à un ERP.
Dès lors comment y accéder depuis d’autres applications sans créer de nouveaux référentiels dont la multiplication ne fera que diminuer la qualité des données et la capacité future à changer de fournisseur de service ?
Une solution consiste à utiliser une norme largement utilisée : VCARD (https://fr.wikipedia.org/wiki/VCard) et CardDAV (https://fr.wikipedia.org/wiki/CardDAV)
VCARD
Utilisé depuis de longues années par Outlook, Google et tous vos Android, échangé régulièrement par email, ce format texte de description des informations d’un contact est relativement simple.
BEGIN:VCARD
VERSION:2.1
N;LANGUAGE=fr;CHARSET=utf-8:GILBART;Frédéric
FN;CHARSET=utf-8:Frédéric GILBART
ORG:CAPSIEL
TITLE:Directeur
TEL;WORK;VOICE:+33 (0) 972571595
NOTE:
END:VCARD
L’avantage : il est facilement lu par de nombreuses librairies dans tous les langages. Un simple fichier texte peut en contenir des milliers.
Voir la RFC complète : https://tools.ietf.org/html/rfc6350
CardDAV
CardDAV est un protocole de stockage et d’accès aux VCards : ce qui signifie que vos contacts sauvegardés dans un serveur CardDAV peuvent-être accédés depuis toutes les applications implémentant le protocole normalisé.
Vos contacts peuvent donc être dans un référentiel unique puis accédés à distances, synchronisés et partagés.
Voir la RFC complète : https://tools.ietf.org/html/rfc6352
Synology
Les NAS Synology proposent une application CardDAV Server que nous allons utiliser pour quelques essais.
iCal4j
Nous utiliserons iCal4j comme bibliothèque d’accès Java.
<dependency>
<groupId>org.mnode.ical4j</groupId>
<artifactId>ical4j-connector</artifactId>
<version>0.9.5-SNAPSHOT</version>
</dependency>
Pour cela nous avons besoin d’un PathResolver adapté au Synology :
public class SynologyPathResolver extends PathResolver {
public String getPrincipalPath(String username) {
return "/principals/users/" + username + "/";
}
public String getUserPath(String username) {
return "/addressbooks/users/" + username + "/";
}
}
Connexion
private CardDavStore store = null;
@Before
public void setUp() throws Exception {
URL url = new URL("http://192.168.10.100:8008/");
String prodId = "-//CAPSIEL//CalDAV Client//EN";
store = new CardDavStore(prodId, url, new SynologyPathResolver());
boolean connected = store.connect("login", password.toCharArray());
assertTrue(connected);
}
@Test
public void synologyConnect() throws Exception {
assertTrue(store.isConnected());
}
@After
public void tearDown() {
store.disconnect();
}
Lister tous les contacts
Cela consiste à faire une addressbook-query qui malheureusement ne fonctionne pas, le Synology retournant une erreur “HTTP/1.1 400 Bad Request”. Il faut modifier iCal4j : net.fortuna.ical4j.connector.dav.CardDavCollection
public VCard[] getComponents() throws ObjectStoreException {
try {
DavPropertyNameSet properties = new DavPropertyNameSet();
properties.add(DavPropertyName.GETETAG);
properties.add(CardDavPropertyName.ADDRESS_DATA);
Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().newDocument();
Element filter = DomUtil
.createElement(document, CalDavConstants.PROPERTY_FILTER,
CalDavConstants.CARDDAV_NAMESPACE);
Element calFilter = DomUtil.createElement(document,
CalDavConstants.PROPERTY_COMP_FILTER,
CalDavConstants.CARDDAV_NAMESPACE);
calFilter.setAttribute(CalDavConstants.ATTRIBUTE_NAME,
CalDavConstants.PROPERTY_ADDRESS_DATA);
ReportInfo info = new ReportInfo(ReportMethod.ADDRESSBOOK_QUERY, 1,
properties);
info.setContentElement(filter);
ReportMethod method = new ReportMethod(getPath(), info);
getStore().getClient().execute(method);
if (method.getStatusCode() == DavServletResponse.SC_MULTI_STATUS) {
return method.getVCards();
} else if (method.getStatusCode()
== DavServletResponse.SC_NOT_FOUND) {
return new VCard[0];
}
} catch (IOException e) {
e.printStackTrace();
} catch (DOMException e) {
e.printStackTrace();
} catch (DavException e) {
} catch (ParserConfigurationException e) {
e.printStackTrace();
} /* catch (ParserException e) {
e.printStackTrace();
} */
return new VCard[0];
}
On obtient alors :
@Test
public void getAllContacts() throws Exception {
for (CardDavCollection o : store.getCollections()) {
assertNotNull(o);
for (VCard card : o.getComponents()) {
System.err.println(card.toString());
}
}
}
BEGIN:VCARD
VERSION:3.0
UID:460308fc-fe58-4a57-a2a5-a65457b61cdb
FN:nom2
N:nom2;;;
NOTE:
END:VCARD
BEGIN:VCARD
VERSION:3.0
UID:fe7b0d35-9ddf-4d17-a6fe-11758768e32a
FN:gilb fred
N:gilb;fred;;;
NOTE:
END:VCARD
Faire une recherche précise
Comment indiqué dans la RFC en utilisant à nouveau “addressbook-query” et en précisant le filter de recherche (ici par nom)
<?xml version="1.0" encoding="UTF-8"?>
<C:addressbook-query xmlns:C="urn:ietf:params:xml:ns:carddav">
<D:prop xmlns:D="DAV:">
<D:getetag />
<C:address-data>
<C:prop name="VERSION" />
<C:prop name="UID" />
<C:prop name="FN" />
<C:prop name="TEL" />
</C:address-data>
</D:prop>
<C:filter test="anyof">
<C:prop-filter name="TEL">
<C:text-match collation="i;unicode-casemap" match-type="contains">972571595</C:text-match>
</C:prop-filter>
</C:filter>
</C:addressbook-query>
Réponse : 1 seul contact comme prévu, trouvé via une partie de son téléphone :
BEGIN:VCARD
VERSION:3.0
UID:fe7b0d35-9ddf-4d17-a6fe-11758768e32a
FN:gilb fred
N:gilb;fred;;;
TEL;TYPE=Default:+33 (0) 972571595
END:VCARD
Ajout d’un nouveau contact
@Test
public void addContact() throws Exception {
VCard card = new VCard();
card.getProperties().add(Version.VERSION_4_0);
card.getProperties().add(new Uid(URI.create(UUID.randomUUID().toString())));
card.getProperties().add(new Fn("fullname"));
card.getProperties().add(new Email("email@domain"));
card.getProperties().add(new Telephone("email@domain"));
for (CardDavCollection o : store.getCollections()) {
assertNotNull(o);
o.addCard(card);
}
}
Liste des serveurs CardDAV
- http://davmail.sourceforge.net/
- https://www.apereo.org/projects/bedework
- http://radicale.org/user_documentation/#idinstallation
- https://github.com/fruux/Baikal
- http://sabre.io
Liste plus complète : https://devguide-calconnect.rhcloud.com/CardDAV/Client-Implementations