001/** 002 * Copyright 2005-2016 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 edu.sampleu.travel.workflow; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.util.ConcreteKeyValue; 020import org.kuali.rice.kew.api.WorkflowRuntimeException; 021import org.kuali.rice.kew.api.identity.Id; 022import org.kuali.rice.kew.api.identity.PrincipalId; 023import org.kuali.rice.kew.api.identity.PrincipalName; 024import org.kuali.rice.kew.api.rule.RoleName; 025import org.kuali.rice.kew.api.user.UserId; 026import org.kuali.rice.kew.engine.RouteContext; 027import org.kuali.rice.kew.exception.WorkflowServiceErrorImpl; 028import org.kuali.rice.kew.routeheader.DocumentContent; 029import org.kuali.rice.kew.rule.GenericRoleAttribute; 030import org.kuali.rice.kew.rule.QualifiedRoleName; 031import org.kuali.rice.kew.rule.ResolvedQualifiedRole; 032import org.kuali.rice.kim.api.identity.principal.Principal; 033import org.kuali.rice.kim.api.services.KimApiServiceLocator; 034import org.kuali.rice.kns.web.ui.Field; 035import org.kuali.rice.kns.web.ui.Row; 036 037import java.util.ArrayList; 038import java.util.Collections; 039import java.util.HashMap; 040import java.util.List; 041import java.util.Map; 042 043/** 044 * An attribute implementation that can resolve organizational roles 045 */ 046public class EmployeeAttribute extends GenericRoleAttribute { 047 private static final RoleName EMPLOYEE_ROLE = new RoleName(EmployeeAttribute.class.getName(), "employee", "Employee"); 048 private static final RoleName SUPERVISOR_ROLE = new RoleName(EmployeeAttribute.class.getName(), "supervisr", "Supervisor"); 049 private static final RoleName DIRECTOR_ROLE = new RoleName(EmployeeAttribute.class.getName(), "director", "Dean/Director"); 050 private static final List<RoleName> ROLES; 051 static { 052 List<RoleName> tmp = new ArrayList<RoleName>(1); 053 tmp.add(EMPLOYEE_ROLE); 054 tmp.add(SUPERVISOR_ROLE); 055 tmp.add(DIRECTOR_ROLE); 056 ROLES = Collections.unmodifiableList(tmp); 057 } 058 059 private static String USERID_FORM_FIELDNAME = "userid"; 060 061 /** 062 * Traveler to be set by client application so that doc content can be generated appropriately 063 */ 064 private String traveler; 065 066 //private AttributeParser _attributeParser = new AttributeParser(ATTRIBUTE_TAGNAME); 067 068 public EmployeeAttribute() { 069 super("employee"); 070 } 071 072 public EmployeeAttribute(String traveler) { 073 super("employee"); 074 this.traveler = traveler; 075 } 076 077 /** for edoclite?? */ 078 public void setTraveler(String traveler) { 079 this.traveler = traveler; 080 } 081 082 /* RoleAttribute methods */ 083 public List<RoleName> getRoleNames() { 084 return ROLES; 085 } 086 087 protected boolean isValidRole(String roleName) { 088 for (RoleName role: ROLES) { 089 if (role.getBaseName().equals(roleName)) { 090 return true; 091 } 092 } 093 return false; 094 } 095 096 097 @Override 098 protected List<String> getRoleNameQualifiers(String roleName, DocumentContent documentContent) { 099 if (!isValidRole(roleName)) { 100 throw new WorkflowRuntimeException("Invalid role: " + roleName); 101 } 102 103 List<String> qualifiers = new ArrayList<String>(); 104 qualifiers.add(roleName); 105 // find all traveller inputs in incoming doc 106// List<Map<String, String>> attrs; 107// try { 108// attrs = content.parseContent(documentContent.getAttributeContent()); 109// } catch (XPathExpressionException xpee) { 110// throw new WorkflowRuntimeException("Error parsing attribute content: " + XmlJotter.jotNode(documentContent.getAttributeContent())); 111// } 112// for (Map<String, String> props: attrs) { 113// String attrTraveler = props.get("traveler"); 114// if (attrTraveler != null) { 115// qualifiers.add(attrTraveler); 116// } 117// } 118 return qualifiers; 119 } 120 121 @Override 122 protected ResolvedQualifiedRole resolveQualifiedRole(RouteContext routeContext, QualifiedRoleName qualifiedRoleName) { 123 List<Id> recipients = resolveRecipients(routeContext, qualifiedRoleName); 124 ResolvedQualifiedRole rqr = new ResolvedQualifiedRole(getLabelForQualifiedRoleName(qualifiedRoleName), 125 recipients, 126 qualifiedRoleName.getBaseRoleName()); // default to no annotation... 127 return rqr; 128 } 129 130 @Override 131 protected List<Id> resolveRecipients(RouteContext routeContext, QualifiedRoleName qualifiedRoleName) { 132 List<Id> members = new ArrayList<Id>(); 133 UserId roleUserId = null; 134 String roleName = qualifiedRoleName.getBaseRoleName(); 135 String roleTraveler = qualifiedRoleName.getQualifier(); 136 137 /* EMPLOYEE role routes to traveler */ 138 if (StringUtils.equals(EMPLOYEE_ROLE.getBaseName(), roleName)) { 139 roleUserId = new PrincipalId(roleTraveler); 140 141 /* SUPERVISOR role routes to... supervisor */ 142 } else if (StringUtils.equals(SUPERVISOR_ROLE.getBaseName(), roleName)) { 143 // HACK: need to create an organizational-hierarchy service which 144 // has methods like 145 // getSupervisor( user ), getDirector( user ), getSupervised( user 146 // ), etc. 147 // using q.uhuuid() as input 148 roleUserId = new PrincipalName("supervisr"); 149 150 /* SUPERVISOR role routes to... director */ 151 } else if (StringUtils.equals(DIRECTOR_ROLE.getBaseName(), roleName)) { 152 // HACK: need to create an organizational-hierarchy service which 153 // has methods like 154 // getSupervisor( user ), getDirector( user ), getSupervised( user 155 // ), etc. 156 // using q.uhuuid() as input 157 roleUserId = new PrincipalName("director"); 158 } else { 159 // throw an exception if you get an unrecognized roleName 160 throw new WorkflowRuntimeException("unable to process unknown role '" + roleName + "'"); 161 } 162 members.add(roleUserId); 163 164 return members; 165 } 166 167 public Map<String, String> getProperties() { 168 Map<String, String> properties = new HashMap<String, String>(); 169 properties.put("traveler", traveler); 170 return properties; 171 } 172 173 /** 174 * Required to support flex routing report 175 * 176 * @see org.kuali.rice.kew.rule.WorkflowRuleAttribute#getFieldConversions() 177 */ 178 public List getFieldConversions() { 179 List conversionFields = new ArrayList(); 180 conversionFields.add(new ConcreteKeyValue("userid", USERID_FORM_FIELDNAME)); 181 return conversionFields; 182 } 183 184 public List<Row> getRoutingDataRows() { 185 List<Row> rows = new ArrayList<Row>(); 186 187 List<Field> fields = new ArrayList<Field>(); 188 fields.add(new Field("Traveler username", "", Field.TEXT, false, USERID_FORM_FIELDNAME, "", false, false, null, null)); 189 rows.add(new Row(fields)); 190 191 return rows; 192 } 193 194 public List validateRoutingData(Map paramMap) { 195 List errors = new ArrayList(); 196 197 String userid = StringUtils.trim((String) paramMap.get(USERID_FORM_FIELDNAME)); 198 if (isRequired() && StringUtils.isBlank(userid)) { 199 errors.add(new WorkflowServiceErrorImpl("userid is required", "uh.accountattribute.userid.required")); 200 } 201 202 Principal principal = null; 203 if (!StringUtils.isBlank(userid)) { 204 principal = KimApiServiceLocator.getIdentityService().getPrincipalByPrincipalName(userid); 205 } 206 if (principal == null) { 207 errors.add(new WorkflowServiceErrorImpl("unable to retrieve user for userid '" + userid + "'", "uh.accountattribute.userid.invalid")); 208 } 209 210 if (errors.size() == 0) { 211 traveler = principal.getPrincipalId(); 212 } 213 214 return errors; 215 } 216}