1 package org.argeo.people.core;
2
3 import static org.argeo.connect.util.ConnectUtils.isEmpty;
4 import static org.argeo.connect.util.ConnectUtils.notEmpty;
5
6 import java.text.SimpleDateFormat;
7 import java.util.ArrayList;
8 import java.util.Calendar;
9 import java.util.GregorianCalendar;
10 import java.util.List;
11
12 import javax.jcr.Node;
13 import javax.jcr.NodeIterator;
14 import javax.jcr.Property;
15 import javax.jcr.RepositoryException;
16 import javax.jcr.Session;
17 import javax.jcr.nodetype.NodeType;
18 import javax.jcr.query.Query;
19 import javax.jcr.query.QueryResult;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.argeo.connect.ConnectNames;
24 import org.argeo.connect.ConnectTypes;
25 import org.argeo.connect.UserAdminService;
26 import org.argeo.connect.core.AbstractAppService;
27 import org.argeo.connect.resources.ResourcesService;
28 import org.argeo.connect.util.ConnectJcrUtils;
29 import org.argeo.connect.util.RemoteJcrUtils;
30 import org.argeo.connect.util.XPathUtils;
31 import org.argeo.jcr.JcrUtils;
32 import org.argeo.people.ContactService;
33 import org.argeo.people.PeopleConstants;
34 import org.argeo.people.PeopleException;
35 import org.argeo.people.PeopleNames;
36 import org.argeo.people.PeopleService;
37 import org.argeo.people.PeopleTypes;
38 import org.argeo.people.PersonService;
39 import org.argeo.people.util.PeopleJcrUtils;
40 import org.argeo.people.util.PersonJcrUtils;
41 import org.osgi.service.useradmin.Role;
42 import org.osgi.service.useradmin.User;
43
44
45 public class PeopleServiceImpl extends AbstractAppService implements PeopleService, PeopleNames {
46 private final static Log log = LogFactory.getLog(PeopleServiceImpl.class);
47
48
49 private ResourcesService resourcesService;
50 private UserAdminService userAdminService;
51
52
53 private PersonService personService;
54 private ContactService contactService = new ContactServiceImpl();
55
56 private SimpleDateFormat usersDatePath = new SimpleDateFormat("YYYY/MM");
57
58 @Override
59 public Node publishEntity(Node parent, String nodeType, Node srcNode, boolean removeSrc)
60 throws RepositoryException {
61 if (PeopleTypes.PEOPLE_PERSON.equals(nodeType) || PeopleTypes.PEOPLE_ORG.equals(nodeType)) {
62 String peopleUid = ConnectJcrUtils.get(srcNode, ConnectNames.CONNECT_UID);
63 if (isEmpty(peopleUid))
64 throw new PeopleException(
65 "Unable to define default path for " + srcNode + ". No property people:uid is defined");
66
67 String relPath = getDefaultRelPath(srcNode);
68 Node createdNode = JcrUtils.mkdirs(parent, relPath);
69
70
71 Node personCreatedNode = null;
72 if (srcNode.hasNode(PeopleNames.PEOPLE_ROLE)) {
73 Node subNode = srcNode.getNode(PeopleNames.PEOPLE_ROLE);
74 String personRelPath = getDefaultRelPath(subNode);
75 personCreatedNode = JcrUtils.mkdirs(parent, personRelPath);
76 RemoteJcrUtils.copy(subNode, personCreatedNode, true);
77 personCreatedNode.addMixin(PeopleTypes.PEOPLE_PERSON);
78
79 subNode.removeMixin(PeopleTypes.PEOPLE_PERSON);
80 subNode.remove();
81 }
82
83 RemoteJcrUtils.copy(srcNode, createdNode, true);
84 createdNode.addMixin(nodeType);
85
86 configureUser(createdNode);
87 if (personCreatedNode != null) {
88 configureUser(personCreatedNode);
89 JcrUtils.updateLastModified(personCreatedNode);
90 }
91 JcrUtils.updateLastModified(createdNode);
92
93 if (removeSrc) {
94 srcNode.removeMixin(nodeType);
95 srcNode.remove();
96 }
97
98 if (personCreatedNode != null) {
99 personService.createOrUpdateJob(null, personCreatedNode, createdNode, null, null, true);
100 }
101 return createdNode;
102 } else
103 return null;
104 }
105
106 private void configureUser(Node createdNode) throws RepositoryException {
107 if (createdNode.hasProperty(PeopleNames.PEOPLE_USERNAME)) {
108 createdNode.addMixin(PeopleTypes.PEOPLE_USER);
109 } else if (createdNode.hasProperty(PeopleNames.PEOPLE_PRIMARY_EMAIL)) {
110 String email = JcrUtils.get(createdNode, PEOPLE_PRIMARY_EMAIL);
111 String dn = userAdminService.buildDefaultDN(email, Role.USER);
112 User user = userAdminService.getUser(dn);
113 if (user == null)
114 user = userAdminService.createUserFromPerson(createdNode);
115 createdNode.addMixin(PeopleTypes.PEOPLE_USER);
116 createdNode.setProperty(PeopleNames.PEOPLE_USERNAME, dn);
117 }
118 }
119
120
121
122
123
124
125
126
127
128
129
130 @Override
131 public Node saveEntity(Node entity, boolean publish) throws PeopleException {
132 try {
133 if (entity.isNodeType(PeopleTypes.PEOPLE_PERSON) || entity.isNodeType(PeopleTypes.PEOPLE_ORG))
134 entity = getPersonService().saveEntity(entity, publish);
135 else
136 throw new PeopleException("Unknown entity type for " + entity);
137 return entity;
138 } catch (RepositoryException e) {
139 throw new PeopleException("Unable to save " + entity, e);
140 }
141 }
142
143 @Override
144 public String getAppBaseName() {
145 return PeopleConstants.PEOPLE_APP_BASE_NAME;
146 }
147
148 @Override
149 public String getBaseRelPath(String nodeType) {
150 if (PeopleTypes.PEOPLE_PERSON.equals(nodeType) || ConnectTypes.CONNECT_LDAP_PERSON.equals(nodeType)
151 || PeopleTypes.PEOPLE_ORG.equals(nodeType) || ConnectTypes.CONNECT_LDAP_ORG.equals(nodeType)
152 || PeopleTypes.PEOPLE_ENTITY.equals(nodeType) || PeopleTypes.PEOPLE_CONTACTABLE.equals(nodeType))
153 return getAppBaseName();
154 else
155 return null;
156 }
157
158 @Override
159 public String getDefaultRelPath(Node entity) throws RepositoryException {
160 Calendar date;
161 if (entity.hasProperty(Property.JCR_CREATED))
162 date = entity.getProperty(Property.JCR_CREATED).getDate();
163 else
164 date = new GregorianCalendar();
165 String creationDatePath = usersDatePath.format(date.getTime());
166
167 String fullName;
168 if (entity.hasProperty(PeopleNames.PEOPLE_DISPLAY_NAME))
169 fullName = entity.getProperty(PeopleNames.PEOPLE_DISPLAY_NAME).getString();
170 else if (entity.hasProperty(PeopleNames.PEOPLE_LEGAL_NAME))
171 fullName = entity.getProperty(PeopleNames.PEOPLE_LEGAL_NAME).getString();
172 else
173 throw new IllegalArgumentException("Cannot find full name of " + entity);
174 String relPath = creationDatePath + "/" + fullName;
175 return relPath;
176
177
178
179
180
181
182
183
184 }
185
186 @Override
187 public String getDefaultRelPath(Session session, String nodeType, String peopleUid) {
188
189
190
191
192
193
194 String path = JcrUtils.firstCharsToPath(peopleUid, 2) + "/" + peopleUid;
195 return path;
196 }
197
198 @Override
199 public boolean isKnownType(Node entity) {
200 if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_PERSON)
201 || ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_ORG)
202 || ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_MAILING_LIST))
203 return true;
204 else
205 return false;
206 }
207
208 @Override
209 public boolean isKnownType(String nodeType) {
210 if (PeopleTypes.PEOPLE_PERSON.equals(nodeType) || PeopleTypes.PEOPLE_ORG.equals(nodeType)
211 || PeopleTypes.PEOPLE_MAILING_LIST.equals(nodeType))
212 return true;
213 else
214 return false;
215 }
216
217 @Override
218 public String getMainNodeType(Node entity) {
219 if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_PERSON))
220 return PeopleTypes.PEOPLE_PERSON;
221 else if (ConnectJcrUtils.isNodeType(entity, ConnectTypes.CONNECT_LDAP_PERSON))
222 return ConnectTypes.CONNECT_LDAP_PERSON;
223 if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_ORG))
224 return PeopleTypes.PEOPLE_ORG;
225 else if (ConnectJcrUtils.isNodeType(entity, ConnectTypes.CONNECT_LDAP_ORG))
226 return ConnectTypes.CONNECT_LDAP_ORG;
227 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_MAILING_LIST))
228 return PeopleTypes.PEOPLE_MAILING_LIST;
229 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_MOBILE))
230 return PeopleTypes.PEOPLE_MOBILE;
231 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_TELEPHONE_NUMBER))
232 return PeopleTypes.PEOPLE_TELEPHONE_NUMBER;
233 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_FAX))
234 return PeopleTypes.PEOPLE_FAX;
235 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_PHONE))
236 return PeopleTypes.PEOPLE_PHONE;
237 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_MAIL))
238 return PeopleTypes.PEOPLE_MAIL;
239 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_URL))
240 return PeopleTypes.PEOPLE_URL;
241 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_SOCIAL_MEDIA))
242 return PeopleTypes.PEOPLE_SOCIAL_MEDIA;
243 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_IMPP))
244 return PeopleTypes.PEOPLE_IMPP;
245 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_POSTAL_ADDRESS))
246 return PeopleTypes.PEOPLE_POSTAL_ADDRESS;
247 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_CONTACT))
248 return PeopleTypes.PEOPLE_CONTACT;
249 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_JOB))
250 return PeopleTypes.PEOPLE_JOB;
251 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_POSITION))
252 return PeopleTypes.PEOPLE_POSITION;
253 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_BANK_ACCOUNT))
254 return PeopleTypes.PEOPLE_BANK_ACCOUNT;
255 else if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_MEMBER))
256 return PeopleTypes.PEOPLE_MEMBER;
257 else
258 return null;
259 }
260
261 @Override
262 public String getDisplayName(Node entity) {
263 String displayName = null;
264 try {
265 if (entity.hasProperty(PEOPLE_DISPLAY_NAME))
266 displayName = entity.getProperty(PEOPLE_DISPLAY_NAME).getString();
267 else if (entity.isNodeType(PeopleTypes.PEOPLE_PERSON))
268 displayName = getPersonService().getDefaultDisplayName(entity);
269 else if (entity.isNodeType(NodeType.MIX_TITLE))
270 displayName = ConnectJcrUtils.get(entity, Property.JCR_TITLE);
271 else
272 throw new PeopleException("Display name not defined for type " + entity.getPrimaryNodeType().getName()
273 + " - node: " + entity);
274 } catch (RepositoryException e) {
275 throw new PeopleException("Unable to get display name for node " + entity, e);
276 }
277 return displayName;
278 }
279
280
281
282
283 @Override
284 public void updatePrimaryCache(Node entity) throws PeopleException, RepositoryException {
285 if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_PERSON)
286 || ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_ORG)) {
287 for (String currType : PeopleTypes.KNOWN_CONTACT_TYPES) {
288 Node pNode = PeopleJcrUtils.getPrimaryContact(entity, currType);
289 if (pNode != null)
290 PeopleJcrUtils.updatePrimaryCache(resourcesService, this, entity, pNode, true);
291 }
292
293
294 if (ConnectJcrUtils.isNodeType(entity, PeopleTypes.PEOPLE_PERSON)) {
295 Node pJob = PersonJcrUtils.getPrimaryJob(entity);
296 if (pJob != null)
297 PeopleJcrUtils.updatePrimaryCache(resourcesService, this, entity, pJob, true);
298 }
299 } else
300 log.warn("Trying to update primary cache on " + entity + " - Unknown type.");
301 }
302
303 @Override
304 public Node getEntityFromNodeReference(Node node, String propName) {
305 try {
306 String peopleUid = ConnectJcrUtils.get(node, propName);
307 if (isEmpty(peopleUid))
308 return null;
309 else
310 return getEntityByUid(node.getSession(), null, peopleUid);
311 } catch (RepositoryException re) {
312 throw new PeopleException(
313 "unable to get entity from reference node " + node + " with ref property " + propName, re);
314 }
315 }
316
317
318
319
320
321 @Override
322 public Node createEntityReference(Node referencingNode, Node referencedNode, String role) {
323 try {
324 Node parentNode = null;
325 String linkNodeType = null;
326 if (referencingNode.isNodeType(PeopleTypes.PEOPLE_PERSON)) {
327 if (referencedNode.isNodeType(PeopleTypes.PEOPLE_ORG)) {
328 linkNodeType = PeopleTypes.PEOPLE_JOB;
329 parentNode = referencingNode.getNode(PeopleNames.PEOPLE_JOBS);
330 }
331 } else if (referencingNode.isNodeType(PeopleTypes.PEOPLE_GROUP)) {
332 if (referencedNode.isNodeType(PeopleTypes.PEOPLE_ORG)
333 || referencedNode.isNodeType(PeopleTypes.PEOPLE_PERSON)
334 || (referencedNode.isNodeType(PeopleTypes.PEOPLE_GROUP)
335 && referencedNode.getIdentifier() != referencingNode.getIdentifier())) {
336 linkNodeType = PeopleTypes.PEOPLE_MEMBER;
337 parentNode = referencingNode.getNode(PeopleNames.PEOPLE_MEMBERS);
338 }
339 }
340 if (parentNode == null || linkNodeType == null)
341 throw new PeopleException(
342 "Unsupported reference: from " + referencingNode + "(" + referencingNode.getPrimaryNodeType()
343 + ")" + " to " + referencedNode + "(" + referencedNode.getPrimaryNodeType() + ")");
344
345
346 if (!ConnectJcrUtils.checkCOStatusBeforeUpdate(referencingNode))
347 log.warn("Referencing node " + referencingNode + " was checked in when we wanted to update");
348
349 Node link = parentNode.addNode(notEmpty(role) ? role : "Unnamed_role", linkNodeType);
350 if (notEmpty(role))
351 link.setProperty(PeopleNames.PEOPLE_ROLE, role);
352 link.setProperty(PeopleNames.PEOPLE_REF_UID,
353 referencedNode.getProperty(ConnectNames.CONNECT_UID).getString());
354 referencingNode.getSession().save();
355
356 return link;
357 } catch (RepositoryException e) {
358 throw new PeopleException("Unable to retrieve related entities", e);
359 }
360 }
361
362 @Override
363 public List<Node> getRelatedEntities(Node entity, String linkNodeType, String relatedEntityType) {
364 try {
365 if (!entity.hasProperty(ConnectNames.CONNECT_UID))
366 return null;
367 String xpathQueryStr = "//element(*, " + linkNodeType + ")";
368 String attrQuery = XPathUtils.getPropertyEquals(PeopleNames.PEOPLE_REF_UID,
369 entity.getProperty(ConnectNames.CONNECT_UID).getString());
370 if (notEmpty(attrQuery))
371 xpathQueryStr += "[" + attrQuery + "]";
372 Query xpathQuery = XPathUtils.createQuery(entity.getSession(), xpathQueryStr);
373 QueryResult result = xpathQuery.execute();
374 NodeIterator ni = result.getNodes();
375 if (relatedEntityType == null)
376 return JcrUtils.nodeIteratorToList(ni);
377 else {
378 List<Node> cleaned = new ArrayList<Node>();
379 while (ni.hasNext()) {
380 Node currNode = ni.nextNode();
381 if (currNode.getParent().getParent().isNodeType(relatedEntityType))
382 cleaned.add(currNode);
383 }
384 return cleaned;
385 }
386 } catch (RepositoryException e) {
387 throw new PeopleException("Unable to retrieve " + linkNodeType + " related "
388 + (relatedEntityType == null ? "" : relatedEntityType) + " entities for " + entity, e);
389 }
390 }
391
392
393 @Override
394 public PersonService getPersonService() {
395 return personService;
396 }
397
398 @Override
399 public ContactService getContactService() {
400 return contactService;
401 }
402
403
404
405
406
407
408 @Deprecated
409 public void init() {
410 personService = new PersonServiceImpl(this, resourcesService);
411 if (log.isDebugEnabled())
412 log.info("People's backend has been initialized");
413 }
414
415
416 public void destroy() {
417 }
418
419
420 public void setResourcesService(ResourcesService resourcesService) {
421 this.resourcesService = resourcesService;
422 personService = new PersonServiceImpl(this, resourcesService);
423 }
424
425 public void setUserAdminService(UserAdminService userAdminService) {
426 this.userAdminService = userAdminService;
427 }
428
429 }