View Javadoc

1   /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   */
15  
16  /**
17   * 
18   */
19  package org.kuali.student.lum.kim;
20  
21  import java.util.ArrayList;
22  import java.util.HashMap;
23  import java.util.HashSet;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import javax.xml.namespace.QName;
30  
31  import org.apache.commons.lang.StringUtils;
32  import org.apache.log4j.Logger;
33  import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
34  import org.kuali.rice.kew.dto.DocumentDetailDTO;
35  import org.kuali.rice.kew.dto.DocumentTypeDTO;
36  import org.kuali.rice.kew.service.KEWServiceLocator;
37  import org.kuali.rice.kew.service.WorkflowUtility;
38  import org.kuali.rice.kim.bo.impl.KimAttributes;
39  import org.kuali.rice.kim.bo.types.dto.AttributeSet;
40  import org.kuali.rice.kim.service.support.impl.KimTypeAttributeValidationException;
41  import org.kuali.student.common.rice.StudentIdentityConstants;
42  import org.kuali.student.core.proposal.dto.ProposalInfo;
43  import org.kuali.student.core.proposal.service.ProposalService;
44  
45  /**
46   * Class to allow convenience methods to help with qualification verification and translation
47   *
48   */
49  public class KimQualificationHelper {
50      protected static final Logger LOG = Logger.getLogger(KimQualificationHelper.class);
51  
52  	private static UniqueMap translationMap = new UniqueMap();
53  
54  	{
55  	    // below is example of how this could work
56  	    // translationMap.put("referenceType.clu.proposal", "kuali.proposal.type.course.create");
57  	}
58  
59  	protected static WorkflowUtility getWorkflowUtility() {
60  		return KEWServiceLocator.getWorkflowUtilityService();
61  	}
62  
63      public static void validateRequiredAttributesAgainstReceived(Set<List<String>> requiredAttributes, AttributeSet receivedAttributes, boolean checkRequiredAttributes, String commaSeparatorString) {
64  		// abort if type does not want the qualifiers to be checked
65  		if ( !checkRequiredAttributes ) {
66  			return;
67  		}
68  		// abort if the list is empty, no attributes need to be checked
69  		if ( requiredAttributes == null || requiredAttributes.isEmpty() ) {
70  			return;
71  		}
72  		// if attributes are null or empty, they're all missing
73  		if ( receivedAttributes == null || receivedAttributes.isEmpty() ) {
74  			return;		
75  		}
76  		
77  		Set<List<String>> totalMissingAttributes = new HashSet<List<String>>();
78  		for (List<String> currentReqAttributes : requiredAttributes) {
79  			List<String> missingAttributes = new ArrayList<String>();
80  			for( String requiredAttribute : currentReqAttributes ) {
81  				if( !receivedAttributes.containsKey(requiredAttribute) ) {
82  					missingAttributes.add(requiredAttribute);
83  				}
84  			}
85  			if (missingAttributes.isEmpty()) {
86  				// if no missing attributes from this list then we have required attributes needed
87  				return;
88  			}
89  			totalMissingAttributes.add(missingAttributes);
90          }
91  
92  		int i = 1;
93      	StringBuffer errorMessage = new StringBuffer("Missing Required Attributes from lists - ");
94      	for (List<String> missingAttributes : totalMissingAttributes) {
95              if(missingAttributes.size()>0) {
96              	errorMessage.append("List " + i + ": (");
97              	i++;
98              	Iterator<String> attribIter = missingAttributes.iterator();
99              	while ( attribIter.hasNext() ) {
100             		errorMessage.append( attribIter.next() );
101             		if( attribIter.hasNext() ) {
102             			errorMessage.append( commaSeparatorString );
103             		}
104             	}
105             	errorMessage.append(")");
106             }
107         }
108 		LOG.info("Found missing attributes: " + errorMessage.toString());
109         throw new KimTypeAttributeValidationException(errorMessage.toString());
110     }
111 
112     protected static String getProposalId(AttributeSet qualification) {
113         for (String proposalReferenceType : StudentIdentityConstants.QUALIFICATION_PROPOSAL_ID_REF_TYPES) {
114             if (qualification.containsKey(proposalReferenceType)) {
115                 return qualification.get(proposalReferenceType);
116             }
117         }
118         return null;
119     }
120 
121     public static AttributeSet translateInputAttributeSet(AttributeSet qualification) {
122 		try {
123 			DocumentDetailDTO docDetail = null;
124 			// first get a valid DocumentDetailDTO object if possible
125 			String documentNumber = qualification.get(KimAttributes.DOCUMENT_NUMBER);
126 			String proposalId = getProposalId(qualification);
127 			if (StringUtils.isBlank(documentNumber)) {
128 			    // if document number is not in qualification try to get it using proposal id qualification
129 	            if (StringUtils.isNotBlank(proposalId)) {
130 	                ProposalInfo propInfo = getProposalService().getProposal(proposalId);
131 	                documentNumber = propInfo.getWorkflowId();
132 	            }
133 			}
134 			if (StringUtils.isNotBlank(documentNumber)) {
135 				// document id exists so look up KEW document instance using it
136 				docDetail = getWorkflowUtility().getDocumentDetail(Long.valueOf(documentNumber));
137 			}
138 			else {
139 				// document id does not exist so attempt lookup by Document Type Name and Application ID
140 				String appId = qualification.get( StudentIdentityConstants.QUALIFICATION_KEW_OBJECT_ID );
141 				if (StringUtils.isNotBlank(appId)) {
142 					String documentTypeName = qualification.get( KimAttributes.DOCUMENT_TYPE_NAME );
143 					if (StringUtils.isBlank(documentTypeName)) {
144 						// could not find Document Type Name in qualification so check for KS Object Type
145 						String ksObjectType = qualification.get( StudentIdentityConstants.QUALIFICATION_KEW_OBJECT_TYPE );
146 						if (StringUtils.isNotBlank(ksObjectType)) {
147 							documentTypeName = translationMap.get(ksObjectType);
148 						}
149 					}
150 					// check for a valid Document Type Name
151 					if (StringUtils.isNotBlank(documentTypeName)) {
152 						// found valid Application ID and Document Type Name so KEW Document instance can be retrieved
153 						docDetail = getWorkflowUtility().getDocumentDetailFromAppId(documentTypeName, appId);
154 					}
155 					else {
156 						// if neither Document Type Name nor KS object type is found then KEW document instance cannot be retrieved
157 						LOG.warn("Could not find valid document type name or KS object type using qualifications: " + qualification);
158 					}
159 				}
160 				else {
161 					// if application id is not found then KEW document instance cannot be retrieved
162 					LOG.warn("Could not find valid document id or application id using qualifications: " + qualification);
163 				}
164 			}
165 			translateQualifications(docDetail, proposalId, qualification);
166 		    return qualification;
167 	    }
168 		catch (Exception e) {
169             LOG.error(e.getLocalizedMessage(), e);
170             throw new RuntimeException(e);
171 		}
172 	}
173 
174 	protected static void translateQualifications(DocumentDetailDTO docDetail, String proposalId, AttributeSet qualifications) {
175 		if (docDetail != null) {
176 			// add document id if necessary
177 			if (!qualifications.containsKey(KimAttributes.DOCUMENT_NUMBER)) {
178 				qualifications.put(KimAttributes.DOCUMENT_NUMBER, docDetail.getRouteHeaderId().toString());
179 			}
180 			// add KS proposal id if possible
181 			if (!qualifications.containsKey(StudentIdentityConstants.QUALIFICATION_KS_PROPOSAL_ID) && StringUtils.isNotBlank(proposalId)) {
182 			    qualifications.put(StudentIdentityConstants.QUALIFICATION_KS_PROPOSAL_ID, proposalId);
183 			}
184 			// add KS object id if necessary
185 			if (!qualifications.containsKey(StudentIdentityConstants.QUALIFICATION_KEW_OBJECT_ID)) {
186 				qualifications.put(StudentIdentityConstants.QUALIFICATION_KEW_OBJECT_ID, docDetail.getAppDocId());
187 			}
188 			DocumentTypeDTO docType = KEWServiceLocator.getDocumentTypeService().getDocumentTypeVO(docDetail.getDocTypeId());
189 			if (docType != null) {
190 				String documentTypeName = docType.getName();
191 				// add document type name if necessary
192 				if (!qualifications.containsKey(KimAttributes.DOCUMENT_TYPE_NAME)) {
193 					qualifications.put(KimAttributes.DOCUMENT_TYPE_NAME, documentTypeName);
194 				}
195 				// add KS object type code if necessary
196 				if (!qualifications.containsKey(StudentIdentityConstants.QUALIFICATION_KEW_OBJECT_TYPE)) {
197 					qualifications.put(StudentIdentityConstants.QUALIFICATION_KEW_OBJECT_TYPE, translationMap.getKeyForValue(documentTypeName));
198 				}
199 			}
200 			else {
201 				String errorMsg = "Could not find valid KEW document type for document id " + docDetail.getRouteHeaderId(); 
202 				LOG.error(errorMsg);
203 				throw new RuntimeException(errorMsg);
204 			}
205 		}
206 		else {
207 			LOG.warn("Could not find KEW document instance for qualifications: " + qualifications);
208 			// add KS object type code if necessary
209 			if ((!qualifications.containsKey(StudentIdentityConstants.QUALIFICATION_KEW_OBJECT_TYPE)) && 
210 					qualifications.containsKey(KimAttributes.DOCUMENT_TYPE_NAME)) {
211 				qualifications.put(StudentIdentityConstants.QUALIFICATION_KEW_OBJECT_TYPE, translationMap.getKeyForValue(qualifications.get(KimAttributes.DOCUMENT_TYPE_NAME)));
212 			}
213 			else if ((!qualifications.containsKey(KimAttributes.DOCUMENT_TYPE_NAME)) && 
214 					qualifications.containsKey(StudentIdentityConstants.QUALIFICATION_KEW_OBJECT_TYPE)) {
215 				qualifications.put(KimAttributes.DOCUMENT_TYPE_NAME, translationMap.get(qualifications.get(StudentIdentityConstants.QUALIFICATION_KEW_OBJECT_TYPE)));
216 			}
217 		}
218 	}
219 
220     protected static ProposalService getProposalService() {
221         return (ProposalService) GlobalResourceLoader.getService(new QName("http://student.kuali.org/wsdl/proposal","ProposalService"));
222     }
223 
224 	private static class UniqueMap extends HashMap<String,String> {
225 
226         private static final long serialVersionUID = 1L;
227 
228 		@Override
229         public String put(String key, String value) {
230 			if (this.containsValue(value)) {
231 				throw new UnsupportedOperationException("Map already contains an entry with value: " + value);
232 			}
233 	        return super.put(key, value);
234         }
235 
236 		public String getKeyForValue(String value) {
237 			for (Map.Entry<String, String> mapEntry : this.entrySet()) {
238 	            if (StringUtils.equals(value, mapEntry.getValue())) {
239 	            	return mapEntry.getKey();
240 	            }
241             }
242 			return null;
243 		}
244 	}
245 
246 }