Browse code

BM-14210 Fix: externalize directory i18n

Thomas Fricker authored on 11/04/2019 10:38:29
Showing 9 changed files
... ...
@@ -27,6 +27,7 @@ import static org.junit.Assert.fail;
27 27
 import java.io.IOException;
28 28
 import java.sql.SQLException;
29 29
 import java.util.Arrays;
30
+import java.util.Collections;
30 31
 import java.util.List;
31 32
 import java.util.UUID;
32 33
 import java.util.concurrent.CountDownLatch;
... ...
@@ -315,6 +316,23 @@ public class DirectoryTests {
315 316
 		assertEquals(u.dataLocation, de.dataLocation);
316 317
 	}
317 318
 
319
+	@Test
320
+	public void testDirEntryI18n() throws ServerFault {
321
+		IDirectory dir = service();
322
+
323
+		// en
324
+		DirEntry entry = dir.getEntry(String.format("%s/%s/%s", domainUid, "addressbooks", "addressbook_" + domainUid));
325
+		assertEquals("Directory", entry.displayName);
326
+
327
+		// fr
328
+		SecurityContext ctxFr = new SecurityContext(null, "system", Collections.emptyList(),
329
+				Arrays.<String>asList(SecurityContext.ROLE_SYSTEM), Collections.emptyMap(), "global.virt", "fr",
330
+				"internal-system", false);
331
+		IDirectory dirFr = ServerSideServiceProvider.getProvider(ctxFr).instance(IDirectory.class, domainUid);
332
+		entry = dirFr.getEntry(String.format("%s/%s/%s", domainUid, "addressbooks", "addressbook_" + domainUid));
333
+		assertEquals("Annuaire", entry.displayName);
334
+	}
335
+
318 336
 	private void waitTaskEnd(TaskRef taskRef) throws ServerFault {
319 337
 		ITask task = ServerSideServiceProvider.getProvider(SecurityContext.SYSTEM).instance(ITask.class, taskRef.id);
320 338
 		while (!task.status().state.ended) {
... ...
@@ -3,6 +3,7 @@
3 3
 <plugin>
4 4
    <extension-point id="net.bluemind.directory.handler" name="directoryHandler" schema="schema/net.bluemind.directory.handler.exsd"/>
5 5
    <extension-point id="net.bluemind.directory.repairSupport" name="repairSupport" schema="schema/net.bluemind.directory.repairSupport.exsd"/>
6
+   <extension-point id="net.bluemind.directory.decorator" name="directoryDecorator" schema="schema/net.bluemind.directory.decorator.exsd"/>
6 7
    <extension
7 8
          point="net.bluemind.core.rest.apiEndpoint">
8 9
       <endpoint
... ...
@@ -71,5 +72,11 @@
71 72
             impl="net.bluemind.directory.service.internal.OrgUnitUserHook">
72 73
       </hook>
73 74
    </extension>
75
+   <extension
76
+         point="net.bluemind.directory.decorator">
77
+      <decorator
78
+            impl="net.bluemind.directory.service.internal.I18nDirectory">
79
+      </decorator>
80
+   </extension>
74 81
 
75 82
 </plugin>
76 83
new file mode 100644
... ...
@@ -0,0 +1,102 @@
1
+<?xml version='1.0' encoding='UTF-8'?>
2
+<!-- Schema file written by PDE -->
3
+<schema targetNamespace="net.bluemind.directory.service" xmlns="http://www.w3.org/2001/XMLSchema">
4
+<annotation>
5
+      <appinfo>
6
+         <meta.schema plugin="net.bluemind.directory.service" id="net.bluemind.directory.decorator" name="directoryDecorator"/>
7
+      </appinfo>
8
+      <documentation>
9
+         [Enter description of this extension point.]
10
+      </documentation>
11
+   </annotation>
12
+
13
+   <element name="extension">
14
+      <annotation>
15
+         <appinfo>
16
+            <meta.element />
17
+         </appinfo>
18
+      </annotation>
19
+      <complexType>
20
+         <sequence>
21
+            <element ref="decorator"/>
22
+         </sequence>
23
+         <attribute name="point" type="string" use="required">
24
+            <annotation>
25
+               <documentation>
26
+                  
27
+               </documentation>
28
+            </annotation>
29
+         </attribute>
30
+         <attribute name="id" type="string">
31
+            <annotation>
32
+               <documentation>
33
+                  
34
+               </documentation>
35
+            </annotation>
36
+         </attribute>
37
+         <attribute name="name" type="string">
38
+            <annotation>
39
+               <documentation>
40
+                  
41
+               </documentation>
42
+               <appinfo>
43
+                  <meta.attribute translatable="true"/>
44
+               </appinfo>
45
+            </annotation>
46
+         </attribute>
47
+      </complexType>
48
+   </element>
49
+
50
+   <element name="decorator">
51
+      <complexType>
52
+         <attribute name="impl" type="string" use="required">
53
+            <annotation>
54
+               <documentation>
55
+                  
56
+               </documentation>
57
+               <appinfo>
58
+                  <meta.attribute kind="java" basedOn=":net.bluemind.directory.service.internal.DirectoryDecorator"/>
59
+               </appinfo>
60
+            </annotation>
61
+         </attribute>
62
+      </complexType>
63
+   </element>
64
+
65
+   <annotation>
66
+      <appinfo>
67
+         <meta.section type="since"/>
68
+      </appinfo>
69
+      <documentation>
70
+         [Enter the first release in which this extension point appears.]
71
+      </documentation>
72
+   </annotation>
73
+
74
+   <annotation>
75
+      <appinfo>
76
+         <meta.section type="examples"/>
77
+      </appinfo>
78
+      <documentation>
79
+         [Enter extension point usage example here.]
80
+      </documentation>
81
+   </annotation>
82
+
83
+   <annotation>
84
+      <appinfo>
85
+         <meta.section type="apiinfo"/>
86
+      </appinfo>
87
+      <documentation>
88
+         [Enter API information here.]
89
+      </documentation>
90
+   </annotation>
91
+
92
+   <annotation>
93
+      <appinfo>
94
+         <meta.section type="implementation"/>
95
+      </appinfo>
96
+      <documentation>
97
+         [Enter information about supplied implementation of this extension point.]
98
+      </documentation>
99
+   </annotation>
100
+
101
+
102
+</schema>
... ...
@@ -18,9 +18,15 @@
18 18
  */
19 19
 package net.bluemind.directory.service;
20 20
 
21
+import java.util.List;
22
+
21 23
 import org.osgi.framework.BundleActivator;
22 24
 import org.osgi.framework.BundleContext;
25
+import org.slf4j.LoggerFactory;
23 26
 
27
+import net.bluemind.directory.service.internal.DirectoryDecorator;
28
+import net.bluemind.directory.service.internal.DirectoryService;
29
+import net.bluemind.eclipse.common.RunnableExtensionLoader;
24 30
 import net.bluemind.hornetq.client.MQ;
25 31
 import net.bluemind.hornetq.client.Topic;
26 32
 
... ...
@@ -37,6 +43,15 @@ public class DirectoryActivator implements BundleActivator {
37 43
 			}
38 44
 		});
39 45
 
46
+		DirectoryService.decorators = loadDecorators();
47
+		LoggerFactory.getLogger(DirectoryActivator.class).info("Loaded {} directory decorators",
48
+				DirectoryService.decorators.size());
49
+
50
+	}
51
+
52
+	private List<DirectoryDecorator> loadDecorators() {
53
+		RunnableExtensionLoader<DirectoryDecorator> loader = new RunnableExtensionLoader<>();
54
+		return loader.loadExtensions("net.bluemind.directory", "decorator", "decorator", "impl");
40 55
 	}
41 56
 
42 57
 	@Override
... ...
@@ -24,7 +24,7 @@ import net.bluemind.core.container.model.ItemValue;
24 24
 import net.bluemind.core.rest.BmContext;
25 25
 import net.bluemind.core.rest.ServerSideServiceProvider;
26 26
 import net.bluemind.directory.api.IDirectory;
27
-import net.bluemind.directory.service.internal.Directory;
27
+import net.bluemind.directory.service.internal.DirectoryService;
28 28
 import net.bluemind.domain.api.Domain;
29 29
 
30 30
 public class DirectoryServiceFactory extends AbstractDirServiceFactory<IDirectory>
... ...
@@ -38,6 +38,6 @@ public class DirectoryServiceFactory extends AbstractDirServiceFactory<IDirector
38 38
 	@Override
39 39
 	protected IDirectory instanceImpl(BmContext context, ItemValue<Domain> domainValue, Container container)
40 40
 			throws ServerFault {
41
-		return new Directory(context, container, domainValue);
41
+		return new DirectoryService(context, container, domainValue);
42 42
 	}
43 43
 }
... ...
@@ -76,7 +76,6 @@ import net.bluemind.core.task.service.ITasksManager;
76 76
 import net.bluemind.directory.api.BaseDirEntry.Kind;
77 77
 import net.bluemind.directory.api.DirEntry;
78 78
 import net.bluemind.directory.api.DirEntryQuery;
79
-import net.bluemind.directory.api.IDirectory;
80 79
 import net.bluemind.directory.persistance.ManageableOrgUnit;
81 80
 import net.bluemind.directory.service.DirEntryHandler;
82 81
 import net.bluemind.directory.service.DirEntryHandlers;
... ...
@@ -84,7 +83,6 @@ import net.bluemind.directory.service.IInCoreDirectory;
84 83
 import net.bluemind.domain.api.Domain;
85 84
 import net.bluemind.exchange.mapi.api.IMapiFolder;
86 85
 import net.bluemind.exchange.mapi.api.IMapiFolderAssociatedInformation;
87
-import net.bluemind.i18n.labels.I18nLabels;
88 86
 import net.bluemind.lib.vertx.VertxPlatform;
89 87
 import net.bluemind.mailbox.api.IMailboxMgmt;
90 88
 import net.bluemind.mailbox.api.IMailboxes;
... ...
@@ -95,7 +93,7 @@ import net.bluemind.server.api.Server;
95 93
 import net.bluemind.tag.api.ITags;
96 94
 import net.bluemind.todolist.api.ITodoList;
97 95
 
98
-public class Directory implements IDirectory {
96
+public class Directory {
99 97
 
100 98
 	private static final Logger logger = LoggerFactory.getLogger(Directory.class);
101 99
 	private BmContext context;
... ...
@@ -114,60 +112,35 @@ public class Directory implements IDirectory {
114 112
 		cache = DirEntriesCache.get(context, domainUid);
115 113
 	}
116 114
 
117
-	@Override
118
-	public DirEntry getRoot() throws ServerFault {
115
+	public ItemValue<DirEntry> getRoot() throws ServerFault {
119 116
 		checkReadAccess();
120
-		ItemValue<DirEntry> itemValue = itemStore.get(domainUid, null);
121
-		if (itemValue != null) {
122
-			return translate(itemValue).value;
123
-		} else {
124
-			return null;
125
-		}
117
+		return itemStore.get(domainUid, null);
126 118
 	}
127 119
 
128
-	@Override
129
-	public DirEntry findByEntryUid(String entryUid) throws ServerFault {
120
+	public ItemValue<DirEntry> findByEntryUid(String entryUid) throws ServerFault {
130 121
 		checkReadAccess();
131
-		ItemValue<DirEntry> itemValue = cache.get(entryUid, () -> itemStore.get(entryUid, null));
132
-		if (itemValue != null && itemValue.value != null) {
133
-			return translate(itemValue).value;
134
-		} else {
135
-			return null;
136
-		}
122
+		return cache.get(entryUid, () -> itemStore.get(entryUid, null));
137 123
 	}
138 124
 
139
-	@Override
140
-	public DirEntry getEntry(String path) throws ServerFault {
125
+	public ItemValue<DirEntry> getEntry(String path) throws ServerFault {
141 126
 		checkReadAccess();
142 127
 		List<ItemValue<DirEntry>> res = itemStore.getEntries(path);
143 128
 		if (res.size() == 1) {
144
-			return translate(res.get(0)).value;
129
+			return res.get(0);
145 130
 		} else if (res.size() > 1) {
146 131
 			logger.warn("more than one entry for path {}", path);
147
-			return translate(res.get(0)).value;
132
+			return res.get(0);
148 133
 		} else {
149 134
 			return null;
150 135
 		}
151 136
 	}
152 137
 
153
-	@Override
154
-	public List<DirEntry> getEntries(String path) throws ServerFault {
138
+	public List<ItemValue<DirEntry>> getEntries(String path) throws ServerFault {
155 139
 		checkReadAccess();
156 140
 		List<ItemValue<DirEntry>> res = itemStore.getEntries(path);
157
-		List<DirEntry> ret = new ArrayList<>(res.size());
158
-		for (ItemValue<DirEntry> entry : res) {
159
-
160
-			// exclude self
161
-			if (entry.value.path.equals(path)) {
162
-				continue;
163
-			}
164
-			translate(entry);
165
-			ret.add(entry.value);
166
-		}
167
-		return ret;
141
+		return res.stream().filter(e -> !e.value.path.equals(path)).collect(Collectors.toList());
168 142
 	}
169 143
 
170
-	@Override
171 144
 	public TaskRef delete(String path) throws ServerFault {
172 145
 		// write access will be tested in handler.entryDeleted
173 146
 		checkReadAccess();
... ...
@@ -185,7 +158,6 @@ public class Directory implements IDirectory {
185 158
 		return handler.entryDeleted(context, domainUid, dir.value.entryUid);
186 159
 	}
187 160
 
188
-	@Override
189 161
 	public TaskRef deleteByEntryUid(String entryUid) throws ServerFault {
190 162
 		checkReadAccess();
191 163
 		ItemValue<DirEntry> dir = itemStore.get(entryUid, null);
... ...
@@ -197,24 +169,20 @@ public class Directory implements IDirectory {
197 169
 		return handler.entryDeleted(context, domainUid, dir.value.entryUid);
198 170
 	}
199 171
 
200
-	@Override
201 172
 	public ContainerChangelog changelog(Long since) throws ServerFault {
202 173
 		checkReadAccess();
203 174
 		return itemStore.changelog(since, Long.MAX_VALUE);
204 175
 	}
205 176
 
206
-	@Override
207 177
 	public ContainerChangeset<String> changeset(Long since) throws ServerFault {
208 178
 		return itemStore.changeset(since, Long.MAX_VALUE);
209 179
 	}
210 180
 
211
-	@Override
212 181
 	public List<ItemValue<DirEntry>> getMultiple(List<String> uids) throws ServerFault {
213 182
 		checkReadAccess();
214 183
 		return itemStore.getMultiple(uids);
215 184
 	}
216 185
 
217
-	@Override
218 186
 	public ListResult<ItemValue<DirEntry>> search(DirEntryQuery query) throws ServerFault {
219 187
 		checkReadAccess();
220 188
 
... ...
@@ -244,18 +212,13 @@ public class Directory implements IDirectory {
244 212
 			List<String> uids = query.entries.subList(from, to);
245 213
 
246 214
 			List<ItemValue<DirEntry>> values = itemStore.getMultiple(uids);
247
-			translate(values);
248 215
 			return ListResult.create(values, query.entries.size());
249 216
 
250 217
 		} else if (query.onlyManagable) {
251 218
 			List<ManageableOrgUnit> manageable = getManageableDirEntries();
252
-			ListResult<ItemValue<DirEntry>> ret = itemStore.searchManageable(query, manageable);
253
-			translate(ret.values);
254
-			return ret;
219
+			return itemStore.searchManageable(query, manageable);
255 220
 		} else {
256
-			ListResult<ItemValue<DirEntry>> ret = itemStore.search(query);
257
-			translate(ret.values);
258
-			return ret;
221
+			return itemStore.search(query);
259 222
 		}
260 223
 	}
261 224
 
... ...
@@ -281,7 +244,6 @@ public class Directory implements IDirectory {
281 244
 		return ret;
282 245
 	}
283 246
 
284
-	@Override
285 247
 	public byte[] getEntryIcon(String entryUid) throws ServerFault {
286 248
 		// FIXME anonymous can read icon ?
287 249
 		// accessManager.checkReadAccess();
... ...
@@ -293,7 +255,6 @@ public class Directory implements IDirectory {
293 255
 		}
294 256
 	}
295 257
 
296
-	@Override
297 258
 	public byte[] getIcon(String path) throws ServerFault {
298 259
 		// FIXME anonymous can read icon ?
299 260
 		// accessManager.checkReadAccess();
... ...
@@ -307,44 +268,23 @@ public class Directory implements IDirectory {
307 268
 
308 269
 	}
309 270
 
310
-	private List<ItemValue<DirEntry>> translate(List<ItemValue<DirEntry>> values) {
311
-
312
-		for (ItemValue<DirEntry> value : values) {
313
-			translate(value);
314
-		}
315
-		return values;
316
-	}
317
-
318
-	private ItemValue<DirEntry> translate(ItemValue<DirEntry> e) {
319
-		if (e != null) {
320
-			e.value.displayName = I18nLabels.getInstance().translate(context.getSecurityContext().getLang(),
321
-					e.value.displayName);
322
-		}
323
-		return e;
324
-	}
325
-
326
-	@Override
327 271
 	public Set<String> getRolesForDirEntry(String entryUid) throws ServerFault {
328 272
 		return new HashSet<>(rbacManager.forEntry(entryUid).roles());
329 273
 	}
330 274
 
331
-	@Override
332 275
 	public Set<String> getRolesForOrgUnit(String ouUid) throws ServerFault {
333 276
 		return new HashSet<>(rbacManager.forOrgUnit(ouUid).roles());
334 277
 	}
335 278
 
336
-	@Override
337 279
 	public ItemValue<VCard> getVCard(String uid) throws ServerFault {
338 280
 		return itemStore.getVCard(uid);
339 281
 	}
340 282
 
341
-	@Override
342 283
 	public byte[] getEntryPhoto(String entryUid) throws ServerFault {
343 284
 		return itemStore.getPhoto(entryUid);
344 285
 	}
345 286
 
346
-	@Override
347
-	public DirEntry getByEmail(String email) throws ServerFault {
287
+	public ItemValue<DirEntry> getByEmail(String email) throws ServerFault {
348 288
 		checkReadAccess();
349 289
 		if (!Regex.EMAIL.validate(email)) {
350 290
 			throw new ServerFault("emailFilter is not valid ", ErrorCode.INVALID_PARAMETER);
... ...
@@ -357,19 +297,13 @@ public class Directory implements IDirectory {
357 297
 			return null;
358 298
 		}
359 299
 
360
-		ItemValue<DirEntry> dirEntry = itemStore.getByEmail(email);
361
-		if (dirEntry != null) {
362
-			return dirEntry.value;
363
-		} else {
364
-			return null;
365
-		}
300
+		return itemStore.getByEmail(email);
366 301
 	}
367 302
 
368 303
 	private void checkReadAccess() {
369 304
 		rbacManager.check(Verb.Read.name(), BasicRoles.ROLE_ADMIN);
370 305
 	}
371 306
 
372
-	@Override
373 307
 	public TaskRef xfer(String entryUid, String serverUid) throws ServerFault {
374 308
 		rbacManager.forEntry(entryUid).check(BasicRoles.ROLE_MANAGE_MAILBOX);
375 309
 
376 310
new file mode 100644
... ...
@@ -0,0 +1,29 @@
1
+/* BEGIN LICENSE
2
+ * Copyright © Blue Mind SAS, 2012-2018
3
+ *
4
+ * This file is part of BlueMind. BlueMind is a messaging and collaborative
5
+ * solution.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of either the GNU Affero General Public License as
9
+ * published by the Free Software Foundation (version 3 of the License).
10
+ *
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
+ *
16
+ * See LICENSE.txt
17
+ * END LICENSE
18
+ */
19
+package net.bluemind.directory.service.internal;
20
+
21
+import net.bluemind.core.container.model.ItemValue;
22
+import net.bluemind.core.rest.BmContext;
23
+import net.bluemind.directory.api.DirEntry;
24
+
25
+public interface DirectoryDecorator {
26
+
27
+	public void decorate(BmContext context, ItemValue<DirEntry> entry);
28
+
29
+}
0 30
new file mode 100644
... ...
@@ -0,0 +1,166 @@
1
+/* BEGIN LICENSE
2
+ * Copyright © Blue Mind SAS, 2012-2018
3
+ *
4
+ * This file is part of BlueMind. BlueMind is a messaging and collaborative
5
+ * solution.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of either the GNU Affero General Public License as
9
+ * published by the Free Software Foundation (version 3 of the License).
10
+ *
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
+ *
16
+ * See LICENSE.txt
17
+ * END LICENSE
18
+ */
19
+package net.bluemind.directory.service.internal;
20
+
21
+import java.util.List;
22
+import java.util.Set;
23
+import java.util.stream.Collectors;
24
+
25
+import net.bluemind.addressbook.api.VCard;
26
+import net.bluemind.core.api.ListResult;
27
+import net.bluemind.core.api.fault.ServerFault;
28
+import net.bluemind.core.container.model.Container;
29
+import net.bluemind.core.container.model.ContainerChangelog;
30
+import net.bluemind.core.container.model.ContainerChangeset;
31
+import net.bluemind.core.container.model.ItemValue;
32
+import net.bluemind.core.rest.BmContext;
33
+import net.bluemind.core.task.api.TaskRef;
34
+import net.bluemind.directory.api.DirEntry;
35
+import net.bluemind.directory.api.DirEntryQuery;
36
+import net.bluemind.directory.api.IDirectory;
37
+import net.bluemind.domain.api.Domain;
38
+
39
+public class DirectoryService implements IDirectory {
40
+
41
+	public static List<DirectoryDecorator> decorators;
42
+
43
+	private final BmContext context;
44
+	private final Directory directory;
45
+
46
+	public DirectoryService(BmContext context, Container dirContainer, ItemValue<Domain> domain) {
47
+		this.context = context;
48
+		this.directory = new Directory(context, dirContainer, domain);
49
+	}
50
+
51
+	@Override
52
+	public DirEntry getRoot() throws ServerFault {
53
+		ItemValue<DirEntry> decorated = decorate(directory.getRoot());
54
+		if (decorated == null) {
55
+			return null;
56
+		}
57
+		return decorated.value;
58
+	}
59
+
60
+	@Override
61
+	public DirEntry getEntry(String path) throws ServerFault {
62
+		ItemValue<DirEntry> decorated = decorate(directory.getEntry(path));
63
+		if (decorated == null) {
64
+			return null;
65
+		}
66
+		return decorated.value;
67
+	}
68
+
69
+	@Override
70
+	public List<DirEntry> getEntries(String path) throws ServerFault {
71
+		return directory.getEntries(path).stream().map(e -> decorate(e)).map(e -> e.value).collect(Collectors.toList());
72
+	}
73
+
74
+	@Override
75
+	public TaskRef delete(String path) throws ServerFault {
76
+		return directory.delete(path);
77
+	}
78
+
79
+	@Override
80
+	public ItemValue<VCard> getVCard(String uid) throws ServerFault {
81
+		return directory.getVCard(uid);
82
+	}
83
+
84
+	@Override
85
+	public TaskRef deleteByEntryUid(String entryUid) throws ServerFault {
86
+		return directory.deleteByEntryUid(entryUid);
87
+	}
88
+
89
+	@Override
90
+	public ContainerChangelog changelog(Long since) throws ServerFault {
91
+		return directory.changelog(since);
92
+	}
93
+
94
+	@Override
95
+	public ContainerChangeset<String> changeset(Long since) throws ServerFault {
96
+		return directory.changeset(since);
97
+	}
98
+
99
+	@Override
100
+	public ListResult<ItemValue<DirEntry>> search(DirEntryQuery query) throws ServerFault {
101
+		ListResult<ItemValue<DirEntry>> search = directory.search(query);
102
+		return ListResult.create(search.values.stream().map(e -> decorate(e)).collect(Collectors.toList()),
103
+				search.total);
104
+	}
105
+
106
+	@Override
107
+	public DirEntry findByEntryUid(String entryUid) throws ServerFault {
108
+		ItemValue<DirEntry> decorated = decorate(directory.findByEntryUid(entryUid));
109
+		if (decorated == null) {
110
+			return null;
111
+		}
112
+		return decorated.value;
113
+	}
114
+
115
+	@Override
116
+	public byte[] getEntryIcon(String entryUid) throws ServerFault {
117
+		return directory.getEntryIcon(entryUid);
118
+	}
119
+
120
+	@Override
121
+	public byte[] getEntryPhoto(String entryUid) throws ServerFault {
122
+		return directory.getEntryPhoto(entryUid);
123
+	}
124
+
125
+	@Override
126
+	public byte[] getIcon(String path) throws ServerFault {
127
+		return directory.getIcon(path);
128
+	}
129
+
130
+	@Override
131
+	public Set<String> getRolesForDirEntry(String entryUid) throws ServerFault {
132
+		return directory.getRolesForDirEntry(entryUid);
133
+	}
134
+
135
+	@Override
136
+	public Set<String> getRolesForOrgUnit(String orgUnitUid) throws ServerFault {
137
+		return directory.getRolesForOrgUnit(orgUnitUid);
138
+	}
139
+
140
+	@Override
141
+	public DirEntry getByEmail(String email) {
142
+		ItemValue<DirEntry> decorated = decorate(directory.getByEmail(email));
143
+		if (decorated == null) {
144
+			return null;
145
+		}
146
+		return decorated.value;
147
+	}
148
+
149
+	@Override
150
+	public List<ItemValue<DirEntry>> getMultiple(List<String> id) {
151
+		return directory.getMultiple(id).stream().map(e -> decorate(e)).collect(Collectors.toList());
152
+	}
153
+
154
+	@Override
155
+	public TaskRef xfer(String entryUid, String serverUid) throws ServerFault {
156
+		return directory.xfer(entryUid, serverUid);
157
+	}
158
+
159
+	private ItemValue<DirEntry> decorate(ItemValue<DirEntry> entry) {
160
+		if (entry != null && entry.value != null) {
161
+			decorators.forEach(decorator -> decorator.decorate(context, entry));
162
+		}
163
+		return entry;
164
+	}
165
+
166
+}
0 167
new file mode 100644
... ...
@@ -0,0 +1,38 @@
1
+/* BEGIN LICENSE
2
+ * Copyright © Blue Mind SAS, 2012-2018
3
+ *
4
+ * This file is part of BlueMind. BlueMind is a messaging and collaborative
5
+ * solution.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of either the GNU Affero General Public License as
9
+ * published by the Free Software Foundation (version 3 of the License).
10
+ *
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
+ *
16
+ * See LICENSE.txt
17
+ * END LICENSE
18
+ */
19
+package net.bluemind.directory.service.internal;
20
+
21
+import net.bluemind.core.container.model.ItemValue;
22
+import net.bluemind.core.rest.BmContext;
23
+import net.bluemind.directory.api.DirEntry;
24
+import net.bluemind.i18n.labels.I18nLabels;
25
+
26
+public class I18nDirectory implements DirectoryDecorator {
27
+
28
+	@Override
29
+	public void decorate(BmContext context, ItemValue<DirEntry> entry) {
30
+		translate(context, entry);
31
+	}
32
+
33
+	private void translate(BmContext context, ItemValue<DirEntry> entry) {
34
+		entry.value.displayName = I18nLabels.getInstance().translate(context.getSecurityContext().getLang(),
35
+				entry.value.displayName);
36
+	}
37
+
38
+}