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