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