001/**
002 * Copyright 2005-2017 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.kew.xml;
017
018import java.io.IOException;
019import java.io.InputStream;
020import java.util.ArrayList;
021import java.util.Collections;
022import java.util.Iterator;
023import java.util.List;
024
025import javax.sql.DataSource;
026import javax.xml.parsers.ParserConfigurationException;
027
028import org.apache.commons.lang.StringUtils;
029import org.jdom.Document;
030import org.jdom.Element;
031import org.jdom.JDOMException;
032import org.jdom.Namespace;
033import org.kuali.rice.core.api.config.ConfigurationException;
034import org.kuali.rice.core.api.util.xml.XmlException;
035import org.kuali.rice.core.api.util.xml.XmlHelper;
036import org.kuali.rice.kim.api.identity.CodedAttribute;
037import org.kuali.rice.kim.api.identity.email.EntityEmail;
038import org.kuali.rice.kim.impl.identity.email.EntityEmailBo;
039import org.kuali.rice.kim.impl.identity.employment.EntityEmploymentBo;
040import org.kuali.rice.kim.impl.identity.entity.EntityBo;
041import org.kuali.rice.kim.impl.identity.name.EntityNameBo;
042import org.kuali.rice.kim.impl.identity.principal.PrincipalBo;
043import org.kuali.rice.kim.impl.identity.type.EntityTypeContactInfoBo;
044import org.kuali.rice.kim.impl.services.KimImplServiceLocator;
045import org.kuali.rice.krad.data.KradDataServiceLocator;
046import org.kuali.rice.krad.data.platform.MaxValueIncrementerFactory;
047import org.xml.sax.SAXException;
048
049/**
050 * Parses users from XML.
051 *
052 * This is really meant for use only in the unit tests and was written to help ease
053 * transition over to KIM.  There are numerous unit tests which took advantage of
054 * the ability to import "users" from XML in KEW.  KIM does not provide XML
055 * import capabilities in the initial implementation so this class provides that.
056 *
057 * @author Kuali Rice Team (rice.collab@kuali.org)
058 *
059 */
060public class UserXmlParser {
061
062    private static final Namespace NAMESPACE = Namespace.getNamespace("", "ns:workflow/User");
063
064    private static final String USERS_ELEMENT = "users";
065    private static final String USER_ELEMENT = "user";
066    private static final String WORKFLOW_ID_ELEMENT = "workflowId";
067    private static final String AUTHENTICATION_ID_ELEMENT = "authenticationId";
068    private static final String PRINCIPAL_ID_ELEMENT = "principalId";
069    private static final String PRINCIPAL_NAME_ELEMENT = "principalName";
070    private static final String EMPL_ID_ELEMENT = "emplId";
071    private static final String EMAIL_ELEMENT = "emailAddress";
072    private static final String GIVEN_NAME_ELEMENT = "givenName";
073    private static final String LAST_NAME_ELEMENT = "lastName";
074    private static final String TYPE_ELEMENT = "type";
075
076    private DataSource kimDataSource;
077
078    public void parseUsers(InputStream input) throws IOException, XmlException {
079        try {
080            Document doc = XmlHelper.trimSAXXml(input);
081            Element root = doc.getRootElement();
082            parseUsers(root);
083        } catch (JDOMException e) {
084            throw new XmlException("Parse error.", e);
085        } catch (SAXException e){
086            throw new XmlException("Parse error.",e);
087        } catch(ParserConfigurationException e){
088            throw new XmlException("Parse error.",e);
089        }
090    }
091
092    public void parseUsers(Element root) throws XmlException {
093        for (Iterator usersElementIt = root.getChildren(USERS_ELEMENT, NAMESPACE).iterator(); usersElementIt.hasNext();) {
094                Element usersElement = (Element) usersElementIt.next();
095                for (Iterator iterator = usersElement.getChildren(USER_ELEMENT, NAMESPACE).iterator(); iterator.hasNext();) {
096                        Element userElement = (Element) iterator.next();
097                        EntityBo entity = constructEntity(userElement);
098                        constructPrincipal(userElement, entity.getId());
099                }
100        }
101    }
102
103    protected EntityBo constructEntity(Element userElement) {
104        String firstName = userElement.getChildTextTrim(GIVEN_NAME_ELEMENT, NAMESPACE);
105        String lastName = userElement.getChildTextTrim(LAST_NAME_ELEMENT, NAMESPACE);
106        String emplId = userElement.getChildTextTrim(EMPL_ID_ELEMENT, NAMESPACE);
107        String entityTypeCode = userElement.getChildTextTrim(TYPE_ELEMENT, NAMESPACE);
108        if (StringUtils.isBlank(entityTypeCode)) {
109                entityTypeCode = "PERSON";
110        }
111
112        Long entityId = new Long(MaxValueIncrementerFactory.getIncrementer(getKimDataSource(), "KRIM_ENTITY_ID_S")
113                .nextLongValue());
114
115        // if they define an empl id, let's set that up
116        EntityEmploymentBo emplInfo = null;
117        if (!StringUtils.isBlank(emplId)) {
118                emplInfo = new EntityEmploymentBo();
119                emplInfo.setActive(true);
120                emplInfo.setEmployeeId(emplId);
121                emplInfo.setPrimary(true);
122                emplInfo.setEntityId("" + entityId);
123                emplInfo.setId(emplId);
124                emplInfo.setEntityAffiliationId(null);
125        }
126
127
128                EntityBo entity = new EntityBo();
129                entity.setActive(true);
130                entity.setId("" + entityId);
131                List<EntityEmploymentBo> emplInfos = new ArrayList<EntityEmploymentBo>();
132                if (emplInfo != null) {
133                        emplInfos.add(emplInfo);
134                }
135                entity.setEmploymentInformation(emplInfos);
136
137                EntityTypeContactInfoBo entityType = new EntityTypeContactInfoBo();
138                entityType.setEntityTypeCode(entityTypeCode);
139                entityType.setEntityId(entity.getId());
140                entityType.setActive(true);
141                String emailAddress = userElement.getChildTextTrim(EMAIL_ELEMENT, NAMESPACE);
142                if (!StringUtils.isBlank(emailAddress)) {
143            Long emailId = new Long(MaxValueIncrementerFactory.getIncrementer(getKimDataSource(),
144                    "KRIM_ENTITY_EMAIL_ID_S").nextLongValue());
145
146                        EntityEmail.Builder email = EntityEmail.Builder.create();
147                        email.setActive(true);
148                        email.setId("" + emailId);
149                        email.setEntityTypeCode(entityTypeCode);
150                        // must be in krim_email_typ_t.email_typ_cd:
151                        email.setEmailType(CodedAttribute.Builder.create("WRK"));
152                        //email.setVersionNumber(new Long(1));
153                        email.setEmailAddress(emailAddress);
154                        email.setDefaultValue(true);
155                        email.setEntityId(entity.getId());
156                        List<EntityEmailBo> emailAddresses = new ArrayList<EntityEmailBo>(1);
157                        emailAddresses.add(EntityEmailBo.from(email.build()));
158                        entityType.setEmailAddresses(emailAddresses);
159                }
160                List<EntityTypeContactInfoBo> entityTypes = new ArrayList<EntityTypeContactInfoBo>(1);
161                entityTypes.add(entityType);
162                entity.setEntityTypeContactInfos(entityTypes);
163
164                if (!StringUtils.isBlank(firstName) || !StringUtils.isBlank(lastName)) {
165            Long entityNameId = MaxValueIncrementerFactory.getIncrementer(getKimDataSource(), "KRIM_ENTITY_NM_ID_S")
166                    .nextLongValue();
167            EntityNameBo name = new EntityNameBo();
168                        name.setActive(true);
169                        name.setId("" + entityNameId);
170                        name.setEntityId(entity.getId());
171                        // must be in krim_ent_nm_typ_t.ent_nm_typ_cd
172                        name.setNameCode("PRFR");
173                        name.setFirstName(firstName);
174                        name.setMiddleName("");
175                        name.setLastName(lastName);
176                        name.setDefaultValue(true);
177
178                        entity.setNames(Collections.singletonList(name));
179                }
180
181                entity =  KradDataServiceLocator.getDataObjectService().save(entity);
182
183                return entity;
184    }
185
186    protected PrincipalBo constructPrincipal(Element userElement, String entityId) {
187        String principalId = userElement.getChildTextTrim(WORKFLOW_ID_ELEMENT, NAMESPACE);
188        if (principalId == null) {
189                principalId = userElement.getChildTextTrim(PRINCIPAL_ID_ELEMENT, NAMESPACE);
190        }
191        String principalName = userElement.getChildTextTrim(AUTHENTICATION_ID_ELEMENT, NAMESPACE);
192        if (principalName == null) {
193                principalName = userElement.getChildTextTrim(PRINCIPAL_NAME_ELEMENT, NAMESPACE);
194        }
195
196                PrincipalBo principal = new PrincipalBo();
197                principal.setActive(true);
198                principal.setPrincipalId(principalId);
199                principal.setPrincipalName(principalName);
200                principal.setEntityId(entityId);
201                principal = KradDataServiceLocator.getDataObjectService().save(principal);
202
203                return principal;
204    }
205
206    public DataSource getKimDataSource() {
207        if (kimDataSource == null) {
208            // TODO - nasty, nasty, nasty - in general the problem here is the fact that UserXmlParser is even using
209            // KIM sequences in the first place
210            kimDataSource = KimImplServiceLocator.getDataSource();
211            if (kimDataSource == null) {
212                throw new ConfigurationException("Failed to locate 'kimDataSource'");
213            }
214        }
215        return kimDataSource;
216    }
217
218    public void setKimDataSource(DataSource kimDataSource) {
219        this.kimDataSource = kimDataSource;
220    }
221}