1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.xml;
17
18 import org.jdom.Document;
19 import org.jdom.Element;
20 import org.jdom.JDOMException;
21 import org.kuali.rice.core.api.util.xml.XmlException;
22 import org.kuali.rice.core.api.util.xml.XmlHelper;
23 import org.kuali.rice.kew.api.KewApiConstants;
24 import org.kuali.rice.kew.util.Utilities;
25 import org.kuali.rice.kim.api.KimConstants;
26 import org.kuali.rice.kim.api.group.Group;
27 import org.kuali.rice.kim.api.group.GroupService;
28 import org.kuali.rice.kim.api.identity.IdentityService;
29 import org.kuali.rice.kim.api.identity.principal.Principal;
30 import org.kuali.rice.kim.api.services.KimApiServiceLocator;
31 import org.kuali.rice.kim.api.type.KimType;
32 import org.kuali.rice.kim.api.type.KimTypeAttribute;
33 import org.xml.sax.SAXException;
34
35 import javax.xml.parsers.ParserConfigurationException;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.util.ArrayList;
39 import java.util.HashMap;
40 import java.util.List;
41 import java.util.Map;
42
43 import static org.kuali.rice.core.api.impex.xml.XmlConstants.*;
44
45
46
47
48
49
50
51
52
53
54 public class GroupXmlParser {
55 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(GroupXmlParser.class);
56 private static final boolean DEFAULT_ACTIVE_VALUE = true;
57 private static final String DEFAULT_GROUP_DESCRIPTION = "";
58 private HashMap<String, List<String>> memberGroupIds = new HashMap<String, List<String>>();
59 private HashMap<String, List<String>> memberGroupNames = new HashMap<String, List<String>>();
60 private HashMap<String, List<String>> memberPrincipalIds = new HashMap<String, List<String>>();
61 private Map<String, String> groupAttributes = new HashMap<String, String>();
62
63 public List<Group> parseGroups(InputStream input) throws IOException, XmlException {
64 try {
65 Document doc = XmlHelper.trimSAXXml(input);
66 Element root = doc.getRootElement();
67 return parseGroups(root);
68 } catch (JDOMException e) {
69 throw new XmlException("Parse error.", e);
70 } catch (SAXException e){
71 throw new XmlException("Parse error.",e);
72 } catch(ParserConfigurationException e){
73 throw new XmlException("Parse error.",e);
74 }
75 }
76
77
78
79
80
81
82
83
84 @SuppressWarnings("unchecked")
85 public List<Group> parseGroups(Element element) throws XmlException {
86 List<Group> groups = new ArrayList<Group>();
87 for (Element groupsElement: (List<Element>) element.getChildren(GROUPS, GROUP_NAMESPACE)) {
88
89 for (Element groupElement: (List<Element>) groupsElement.getChildren(GROUP, GROUP_NAMESPACE)) {
90 groups.add(parseGroup(groupElement));
91 }
92 }
93 for (Group group : groups) {
94 GroupService groupService = KimApiServiceLocator.getGroupService();
95
96 Group foundGroup = groupService.getGroupByNameAndNamespaceCode(group.getNamespaceCode(), group.getName());
97
98 if (foundGroup == null) {
99 if ( LOG.isInfoEnabled() ) {
100 LOG.info("Group named '" + group.getName() + "' not found, creating new group named '" + group.getName() + "'");
101 }
102 try {
103 Group newGroup = groupService.createGroup(group);
104
105 String key = newGroup.getNamespaceCode().trim() + KewApiConstants.KIM_GROUP_NAMESPACE_NAME_DELIMITER_CHARACTER + newGroup.getName().trim();
106 addGroupMembers(newGroup, key);
107 } catch (Exception e) {
108 throw new RuntimeException("Error creating group with name '" + group.getName() + "'", e);
109 }
110 } else {
111 if ( LOG.isInfoEnabled() ) {
112 LOG.info("Group named '" + group.getName() + "' found, creating a new version");
113 }
114 try {
115 Group.Builder builder = Group.Builder.create(foundGroup);
116 builder.setActive(group.isActive());
117 builder.setDescription(group.getDescription());
118 builder.setKimTypeId(group.getKimTypeId());
119
120
121 group = builder.build();
122 groupService.updateGroup(foundGroup.getId(), group);
123
124
125 groupService.removeAllMembers(foundGroup.getId());
126
127 String key = group.getNamespaceCode().trim() + KewApiConstants.KIM_GROUP_NAMESPACE_NAME_DELIMITER_CHARACTER + group.getName().trim();
128 addGroupMembers(group, key);
129
130 } catch (Exception e) {
131 throw new RuntimeException("Error updating group.", e);
132 }
133 }
134 }
135 return groups;
136 }
137
138 @SuppressWarnings("unchecked")
139 private Group parseGroup(Element element) throws XmlException {
140
141
142
143
144 String typeId = null;
145 KimType kimTypeInfo;
146 List<KimTypeAttribute> kimTypeAttributes = new ArrayList<KimTypeAttribute>();
147 if (element.getChild(TYPE, GROUP_NAMESPACE) != null) {
148 Element typeElement = element.getChild(TYPE, GROUP_NAMESPACE);
149 String typeNamespace = typeElement.getChildText(NAMESPACE, GROUP_NAMESPACE);
150 String typeName = typeElement.getChildText(NAME, GROUP_NAMESPACE);
151 kimTypeInfo = KimApiServiceLocator.getKimTypeInfoService().findKimTypeByNameAndNamespace(typeNamespace, typeName);
152 if (kimTypeInfo != null) {
153 typeId = kimTypeInfo.getId();
154 kimTypeAttributes = kimTypeInfo.getAttributeDefinitions();
155 } else {
156 throw new XmlException("Invalid type name and namespace specified.");
157 }
158 } else {
159 kimTypeInfo = KimApiServiceLocator.getKimTypeInfoService().findKimTypeByNameAndNamespace(KimConstants.KIM_TYPE_DEFAULT_NAMESPACE, KimConstants.KIM_TYPE_DEFAULT_NAME);
160 if (kimTypeInfo != null) {
161 typeId = kimTypeInfo.getId();
162 kimTypeAttributes = kimTypeInfo.getAttributeDefinitions();
163 } else {
164 throw new RuntimeException("Failed to locate the 'Default' group type! Please ensure that it's in your database.");
165 }
166 }
167
168
169 String groupNamespace = element.getChildText(NAMESPACE, GROUP_NAMESPACE);
170 if (groupNamespace == null) {
171 throw new XmlException("Namespace must have a value.");
172 }
173
174 String groupName = element.getChildText(NAME, GROUP_NAMESPACE);
175 if (groupName == null) {
176 throw new XmlException("Name must have a value.");
177 }
178
179 Group.Builder groupInfo = Group.Builder.create(groupNamespace, groupName, typeId);
180 IdentityService identityService = KimApiServiceLocator.getIdentityService();
181
182
183 String id = element.getChildText(ID, GROUP_NAMESPACE);
184 if (id != null) {
185 groupInfo.setId(id.trim());
186 } else {
187
188 }
189
190 String description = element.getChildText(DESCRIPTION, GROUP_NAMESPACE);
191 if (description != null && !description.trim().equals("")) {
192 groupInfo.setDescription(description);
193 }
194
195
196 groupInfo.setActive(DEFAULT_ACTIVE_VALUE);
197 if (element.getChildText(ACTIVE, GROUP_NAMESPACE) != null) {
198 String active = element.getChildText(ACTIVE, GROUP_NAMESPACE).trim();
199 if (active.toUpperCase().equals("N") || active.toUpperCase().equals("FALSE")) {
200 groupInfo.setActive(false);
201 }
202 }
203
204
205 List<String> validAttributeKeys = new ArrayList<String>();
206 for (KimTypeAttribute attribute : kimTypeAttributes) {
207 validAttributeKeys.add(attribute.getKimAttribute().getAttributeName());
208 }
209
210 if (element.getChild(ATTRIBUTES, GROUP_NAMESPACE) != null) {
211 List<Element> attributes = element.getChild(ATTRIBUTES, GROUP_NAMESPACE).getChildren();
212
213 Map<String, String> attrMap = new HashMap<String, String>();
214 for (Element attr : attributes ) {
215 attrMap.put(attr.getAttributeValue(KEY), attr.getAttributeValue(VALUE));
216 if (!validAttributeKeys.contains(attr.getAttributeValue(KEY))) {
217 throw new XmlException("Invalid attribute specified.");
218 }
219 }
220 Map<String, String> groupAttributes = attrMap;
221 if (!groupAttributes.isEmpty()) {
222 groupInfo.setAttributes(groupAttributes);
223 }
224 }
225
226
227
228 List<Element> members = null;
229 if(element.getChild(MEMBERS, GROUP_NAMESPACE) == null) {
230 members = new ArrayList<Element>();
231 }
232 else {
233 members = element.getChild(MEMBERS, GROUP_NAMESPACE).getChildren();
234 }
235 for (Element member : members) {
236 String elementName = member.getName().trim();
237 if (elementName.equals(PRINCIPAL_NAME)) {
238 String principalName = member.getText().trim();
239 Principal principal = identityService.getPrincipalByPrincipalName(principalName);
240 if (principal != null) {
241 addPrincipalToGroup(groupInfo.getNamespaceCode(), groupInfo.getName(), principal.getPrincipalId());
242 } else {
243 throw new XmlException("Principal Name "+principalName+" cannot be found.");
244 }
245 } else if (elementName.equals(PRINCIPAL_ID)) {
246 String xmlPrincipalId = member.getText().trim();
247 Principal principal = identityService.getPrincipal(xmlPrincipalId);
248 if (principal != null) {
249 addPrincipalToGroup(groupInfo.getNamespaceCode(), groupInfo.getName(), principal.getPrincipalId());
250 } else {
251 throw new XmlException("Principal Id "+xmlPrincipalId+" cannot be found.");
252 }
253
254 } else if (elementName.equals(GROUP_ID)) {
255 String xmlGroupId = member.getText().trim();
256 addGroupToGroup(groupInfo.getNamespaceCode(), groupInfo.getName(), xmlGroupId);
257 } else if (elementName.equals(GROUP_NAME)) {
258 String xmlGroupName = member.getChildText(NAME, GROUP_NAMESPACE).trim();
259 String xmlGroupNamespace = member.getChildText(NAMESPACE, GROUP_NAMESPACE).trim();
260 addGroupNameToGroup(groupInfo.getNamespaceCode(), groupInfo.getName(), xmlGroupNamespace, xmlGroupName);
261 } else {
262 LOG.error("Unknown member element: " + elementName);
263 }
264
265
266 }
267
268 return groupInfo.build();
269
270 }
271
272 private void addPrincipalToGroup(String groupNamespace, String groupName, String principalId) {
273 String key = groupNamespace.trim() + KewApiConstants.KIM_GROUP_NAMESPACE_NAME_DELIMITER_CHARACTER + groupName.trim();
274 List<String> principalIds = memberPrincipalIds.get(key);
275 if (principalIds == null) {
276 principalIds = new ArrayList<String>();
277 }
278 principalIds.add(principalId);
279 memberPrincipalIds.put(key, principalIds);
280 }
281
282 private void addGroupToGroup(String groupNamespace, String groupName, String groupId) {
283 String key = groupNamespace.trim() + KewApiConstants.KIM_GROUP_NAMESPACE_NAME_DELIMITER_CHARACTER + groupName.trim();
284 List<String> groupIds = memberGroupIds.get(key);
285 if (groupIds == null) {
286 groupIds = new ArrayList<String>();
287 }
288 groupIds.add(groupId);
289 memberGroupIds.put(key, groupIds);
290 }
291
292 private void addGroupNameToGroup(String groupNamespace, String groupName, String memberGroupNamespace, String memberGroupName) {
293 String key = groupNamespace.trim() + KewApiConstants.KIM_GROUP_NAMESPACE_NAME_DELIMITER_CHARACTER + groupName.trim();
294 List<String> groupNames = memberGroupNames.get(key);
295 if (groupNames == null) {
296 groupNames = new ArrayList<String>();
297 }
298 groupNames.add(memberGroupNamespace.trim() + KewApiConstants.KIM_GROUP_NAMESPACE_NAME_DELIMITER_CHARACTER + memberGroupName.trim());
299 memberGroupNames.put(key, groupNames);
300 }
301
302 private void addGroupMembers(Group groupInfo, String key) throws XmlException {
303 GroupService groupService = KimApiServiceLocator.getGroupService();
304 List<String> groupIds = memberGroupIds.get(key);
305 if (groupIds != null) {
306 for (String groupId : groupIds) {
307 Group group = groupService.getGroup(groupId);
308 if (group != null) {
309 groupService.addGroupToGroup(group.getId(), groupInfo.getId());
310 } else {
311 throw new XmlException("Group Id "+groupId+" cannot be found.");
312 }
313 }
314 }
315 List<String> groupNames = memberGroupNames.get(key);
316 if (groupNames != null) {
317 for (String groupName : groupNames) {
318 Group group = groupService.getGroupByNameAndNamespaceCode(Utilities.parseGroupNamespaceCode(groupName),
319 Utilities.parseGroupName(groupName));
320 if (group != null) {
321 groupService.addGroupToGroup(group.getId(), groupInfo.getId());
322 } else {
323 throw new XmlException("Group "+groupName+" cannot be found.");
324 }
325 }
326 }
327 List<String> principalIds = memberPrincipalIds.get(key);
328 if (principalIds != null) {
329 for (String principalId : principalIds) {
330 groupService.addPrincipalToGroup(principalId, groupInfo.getId());
331 }
332 }
333
334 }
335 }