1 package org.argeo.people.core;
2
3 import static java.util.Arrays.asList;
4
5 import java.util.ArrayList;
6 import java.util.List;
7
8 import javax.jcr.Node;
9 import javax.jcr.NodeIterator;
10 import javax.jcr.Property;
11 import javax.jcr.PropertyIterator;
12 import javax.jcr.PropertyType;
13 import javax.jcr.RepositoryException;
14 import javax.jcr.Value;
15 import javax.jcr.ValueFactory;
16 import javax.jcr.query.Query;
17 import javax.jcr.query.QueryManager;
18
19 import org.argeo.connect.ConnectNames;
20 import org.argeo.connect.util.ConnectJcrUtils;
21 import org.argeo.people.ImportService;
22 import org.argeo.people.PeopleException;
23 import org.argeo.people.PeopleNames;
24 import org.argeo.people.PeopleService;
25 import org.argeo.people.PeopleTypes;
26
27
28 public class ImportServiceImpl implements ImportService, PeopleNames {
29
30 private final PeopleService peopleService;
31
32 public ImportServiceImpl(PeopleService peopleService) {
33 this.peopleService = peopleService;
34 }
35
36
37 private final List<String> TECHNICAL_PROPERTIES = asList("jcr:uuid", "jcr:baseVersion", "jcr:isCheckedOut",
38 "jcr:predecessors", "jcr:frozenUuid", "jcr:versionHistory", "jcr:frozenPrimaryType", "jcr:primaryType",
39 "jcr:mixinTypes", "jcr:created", "jcr:createdBy", "jcr:lastModified", "jcr:lastModifiedBy");
40
41 private final List<String> TECHNICAL_NODES = asList("rep:policy");
42
43 public void mergeNodes(Node masterNode, Node slaveNode) throws RepositoryException {
44
45 PropertyIterator pit = slaveNode.getProperties();
46 props: while (pit.hasNext()) {
47 Property currProp = pit.nextProperty();
48 if (TECHNICAL_PROPERTIES.contains(currProp.getName()))
49 continue props;
50
51 Property masterCurrProp = null;
52 if (masterNode.hasProperty(currProp.getName()))
53 masterCurrProp = masterNode.getProperty(currProp.getName());
54 mergeProperty(masterNode, masterCurrProp, currProp);
55 }
56
57 NodeIterator nit = slaveNode.getNodes();
58 nodes: while (nit.hasNext()) {
59 Node currNode = nit.nextNode();
60 if (TECHNICAL_NODES.contains(currNode.getName()))
61 continue nodes;
62 Node masterCurrChild = null;
63
64
65 if (masterNode.hasNode(currNode.getName()))
66 masterCurrChild = masterNode.getNode(currNode.getName());
67 else
68 masterCurrChild = masterNode.addNode(currNode.getName(), currNode.getPrimaryNodeType().getName());
69 mergeNodes(masterCurrChild, currNode);
70 }
71
72
73 if (slaveNode.hasProperty(ConnectNames.CONNECT_UID))
74 mergeInternalReferences(masterNode, slaveNode);
75
76 if (slaveNode.isNodeType("mix:referenceable"))
77 mergeJcrReferences(masterNode, slaveNode);
78 }
79
80 protected void mergeJcrReferences(Node masterNode, Node slaveNode) throws RepositoryException {
81 PropertyIterator pit = slaveNode.getReferences();
82 while (pit.hasNext()) {
83 Property ref = pit.nextProperty();
84 Node referencing = ref.getParent();
85
86 if (ref.isMultiple()) {
87 ConnectJcrUtils.removeRefFromMultiValuedProp(referencing, ref.getName(), slaveNode.getIdentifier());
88 ConnectJcrUtils.addRefToMultiValuedProp(referencing, ref.getName(), masterNode);
89 } else
90 referencing.setProperty(ref.getName(), masterNode);
91 }
92 }
93
94 protected void mergeInternalReferences(Node masterNode, Node slaveNode) throws RepositoryException {
95 NodeIterator nit = internalReferencing(slaveNode);
96 String peopleUId = masterNode.getProperty(ConnectNames.CONNECT_UID).getString();
97 while (nit.hasNext()) {
98 Node referencing = nit.nextNode();
99
100 referencing.setProperty(PEOPLE_REF_UID, peopleUId);
101 }
102 }
103
104 protected NodeIterator internalReferencing(Node slaveNode) throws RepositoryException {
105 String peopleUId = slaveNode.getProperty(ConnectNames.CONNECT_UID).getString();
106 QueryManager qm = slaveNode.getSession().getWorkspace().getQueryManager();
107 Query query = qm.createQuery("select * from [nt:base] as nodes where ISDESCENDANTNODE('"
108 + peopleService.getBaseRelPath(PeopleTypes.PEOPLE_ENTITY) + "') AND [" + PEOPLE_REF_UID + "]='"
109 + peopleUId + "'" + " ", Query.JCR_SQL2);
110 return query.execute().getNodes();
111 }
112
113 protected void mergeProperty(Node masterNode, Property masterProp, Property slaveProp) throws RepositoryException {
114 if (slaveProp.isMultiple())
115 mergeMultipleProperty(masterNode, masterProp, slaveProp);
116 else if (masterProp == null) {
117 masterNode.setProperty(slaveProp.getName(), slaveProp.getValue());
118 }
119
120 }
121
122 private void mergeMultipleProperty(Node masterNode, Property masterProp, Property slaveProp)
123 throws RepositoryException {
124 Value[] slaveVals = slaveProp.getValues();
125 if (masterProp == null) {
126 masterNode.setProperty(slaveProp.getName(), slaveVals);
127 } else {
128 Value[] vals = masterProp.getValues();
129 if (vals[0].getType() == PropertyType.STRING) {
130 List<String> res = new ArrayList<String>();
131 for (Value val : vals)
132 res.add(val.getString());
133 for (Value val : slaveVals) {
134 String currStr = val.getString();
135 if (!res.contains(currStr))
136 res.add(currStr);
137 }
138 masterProp.setValue(res.toArray(new String[0]));
139 } else if (vals[0].getType() == PropertyType.REFERENCE) {
140 List<String> res = new ArrayList<String>();
141 for (Value val : vals)
142 res.add(val.getString());
143 for (Value val : slaveVals) {
144 String currStr = val.getString();
145 if (!res.contains(currStr))
146 res.add(currStr);
147 }
148 ValueFactory vFactory = masterNode.getSession().getValueFactory();
149 int size = res.size();
150 Value[] values = new Value[size];
151 int i = 0;
152 for (String id : res) {
153 Value val = vFactory.createValue(id, PropertyType.REFERENCE);
154 values[i++] = val;
155 }
156 masterNode.setProperty(slaveProp.getName(), values);
157 } else {
158 throw new PeopleException(
159 "Unsupported multiple property type on property " + masterProp + "for node " + masterNode);
160 }
161 }
162 }
163 }