View Javadoc
1   /**
2    * Copyright 2014 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   * Created by venkat on 3/3/14
16   */
17  package org.kuali.student.cm.proposal.service.impl;
18  
19  import org.apache.commons.lang.BooleanUtils;
20  import org.apache.commons.lang.StringUtils;
21  import org.kuali.rice.core.api.criteria.PredicateFactory;
22  import org.kuali.rice.core.api.criteria.QueryByCriteria;
23  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
24  import org.kuali.rice.kew.api.exception.WorkflowException;
25  import org.kuali.rice.kim.api.identity.entity.EntityDefault;
26  import org.kuali.rice.kim.api.identity.entity.EntityDefaultQueryResults;
27  import org.kuali.rice.kim.api.identity.principal.Principal;
28  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
29  import org.kuali.rice.krad.document.Document;
30  import org.kuali.rice.krad.lookup.LookupForm;
31  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
32  import org.kuali.rice.krad.uif.UifConstants;
33  import org.kuali.rice.krad.uif.element.Action;
34  import org.kuali.rice.krad.util.GlobalVariables;
35  import org.kuali.student.cm.maintenance.CMMaintenanceDocument;
36  import org.kuali.student.common.uif.service.impl.KSLookupableImpl;
37  import org.kuali.student.common.util.security.ContextUtils;
38  import org.kuali.student.r2.common.dto.AttributeInfo;
39  import org.kuali.student.r2.core.constants.ProposalServiceConstants;
40  import org.kuali.student.r2.core.proposal.dto.ProposalInfo;
41  import org.kuali.student.r2.core.proposal.service.ProposalService;
42  import org.kuali.student.r2.core.search.dto.SearchParamInfo;
43  import org.kuali.student.r2.core.search.dto.SearchRequestInfo;
44  import org.kuali.student.r2.core.search.dto.SearchResultCellInfo;
45  import org.kuali.student.r2.core.search.dto.SearchResultInfo;
46  import org.kuali.student.r2.core.search.dto.SearchResultRowInfo;
47  
48  import javax.xml.namespace.QName;
49  import java.util.ArrayList;
50  import java.util.Collections;
51  import java.util.HashMap;
52  import java.util.List;
53  import java.util.Map;
54  
55  /**
56   * Lookupable class for ProposalInfo objects
57   *
58   * @author Kuali Student Team
59   */
60  public abstract class ProposalLookupableImpl extends KSLookupableImpl {
61  
62      private transient ProposalService proposalService;
63  
64      protected final String PROPOSAL_TITLE_LEY = "proposal.queryParam.proposalOptionalName";
65      protected final String SEARCH_KEY = "proposal.search.generic";
66      protected final String PROPOSAL_ID_KEY = "proposal.resultColumn.proposalId";
67      protected final String CAN_EDIT_PROPOSAL_KEY = "canEditProposal";
68      protected final String CAN_OPEN_PROPOSAL_KEY = "canOpenProposal";
69  
70      @Override
71      public List<?> performSearch(LookupForm lookupForm, Map<String, String> fieldValues, boolean unbounded) {
72  
73          List<SearchParamInfo> searchParams = new ArrayList<SearchParamInfo>();
74  
75          String fieldValue = fieldValues.get("title");
76  
77          SearchParamInfo qpv = new SearchParamInfo();
78          qpv.setKey(PROPOSAL_TITLE_LEY);
79          qpv.getValues().add(fieldValue);
80          searchParams.add(qpv);
81  
82          SearchRequestInfo searchRequest = new SearchRequestInfo();
83          searchRequest.setParams(searchParams);
84          searchRequest.setSearchKey(SEARCH_KEY);
85          searchRequest.setSortColumn(PROPOSAL_TITLE_LEY);
86  
87          List<ProposalInfo> proposalInfos;
88          try {
89              SearchResultInfo searchResult = getProposalService().search(searchRequest, ContextUtils.createDefaultContextInfo());
90              proposalInfos = resolveProposalSearchResultSet(searchResult);
91          } catch (Exception e) {
92              throw new RuntimeException(e);
93          }
94  
95          return proposalInfos;
96      }
97  
98      protected List<ProposalInfo> resolveProposalSearchResultSet(SearchResultInfo searchResult) throws Exception {
99          List<ProposalInfo> proposals = new ArrayList<ProposalInfo>();
100         List<SearchResultRowInfo> rows = searchResult.getRows();
101         List<String> proposalIds = new ArrayList<String>();
102 
103         for (SearchResultRowInfo row : rows) {
104             List<SearchResultCellInfo> cells = row.getCells();
105             for (SearchResultCellInfo cell : cells) {
106                 if (cell.getKey().equals(PROPOSAL_ID_KEY)) {
107                     proposalIds.add(cell.getValue());
108                 }
109             }
110         }
111 
112         if (!proposalIds.isEmpty()){
113             proposals = getProposalService().getProposalsByIds(proposalIds,ContextUtils.createDefaultContextInfo());
114             populateProposalCreatorName(proposals);
115             populateProposalAllowedActions(proposals);
116         }
117 
118         return Collections.unmodifiableList(proposals);
119     }
120 
121     protected void populateProposalCreatorName(List<ProposalInfo> proposals) {
122 
123         if (proposals.isEmpty()){
124             return;
125         }
126 
127         List<String> principalIds = new ArrayList<String>();
128         for (ProposalInfo proposal : proposals){
129             principalIds.add(proposal.getMeta().getCreateId());
130         }
131 
132         QueryByCriteria.Builder qbcBuilder = QueryByCriteria.Builder.create();
133         qbcBuilder.setPredicates(PredicateFactory.in("principals.principalId", principalIds.toArray()));
134 
135         QueryByCriteria criteria = qbcBuilder.build();
136 
137         EntityDefaultQueryResults entityResults = KimApiServiceLocator.getIdentityService().findEntityDefaults(criteria);
138 
139         Map<String,String> principalId2Name = new HashMap<String, String>();
140 
141         for (EntityDefault entity : entityResults.getResults()) {
142             for (Principal principal : entity.getPrincipals()) {
143                 principalId2Name.put(principal.getPrincipalId(), entity.getName().getCompositeName());
144             }
145         }
146 
147         for (ProposalInfo proposal : proposals) {
148             String principalName = principalId2Name.get(proposal.getMeta().getCreateId());
149             /** A hacky way to display the user full name at the UI to avoid creating a new wrapper class.
150              * And, we're returning an unmodifiable list from the search method to make sure it's not
151              * possible to change this object.
152              */
153             proposal.getMeta().setCreateId(principalName);
154         }
155 
156     }
157 
158     protected void populateProposalAllowedActions(List<ProposalInfo> proposals){
159 
160         if (proposals.isEmpty()){
161             return;
162         }
163 
164         List<String> workflowIds = new ArrayList<String>();
165         for (ProposalInfo proposal : proposals){
166             workflowIds.add(proposal.getWorkflowId());
167         }
168 
169         List<Document> documents = null;
170         try {
171             documents = KRADServiceLocatorWeb.getDocumentService()
172                     .getDocumentsByListOfDocumentHeaderIds(CMMaintenanceDocument.class, workflowIds);
173         } catch (WorkflowException e) {
174             throw new RuntimeException("Error loading maintenance document",e);
175         }
176 
177         Map<String,Document> workflowId2Doc = new HashMap<String, Document>();
178 
179         for (Document document : documents){
180             workflowId2Doc.put(document.getDocumentNumber(),document);
181         }
182 
183         for (ProposalInfo proposal : proposals){
184 
185             boolean canEdit;
186             boolean canOpen;
187 
188             Document document = workflowId2Doc.get(proposal.getWorkflowId());
189             String docTypeName = document.getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
190 
191             canEdit = KRADServiceLocatorWeb.getDocumentDictionaryService().getDocumentAuthorizer(docTypeName).canEdit(document,
192                     GlobalVariables.getUserSession().getPerson());
193 
194             canOpen = KRADServiceLocatorWeb.getDocumentDictionaryService().getDocumentAuthorizer(docTypeName).canOpen(document,
195                     GlobalVariables.getUserSession().getPerson());
196 
197             AttributeInfo editAttribute = new AttributeInfo(CAN_EDIT_PROPOSAL_KEY, BooleanUtils.toStringTrueFalse(canEdit));
198             AttributeInfo openAttribute = new AttributeInfo(CAN_OPEN_PROPOSAL_KEY, BooleanUtils.toStringTrueFalse(canOpen));
199             proposal.getAttributes().add(editAttribute);
200             proposal.getAttributes().add(openAttribute);
201         }
202     }
203 
204     /**
205      * Determines if given data object has associated maintenance document that allows edit maintenance
206      * actions
207      *
208      * @return boolean true if the maintenance edit action is allowed for the data object instance, false otherwise
209      */
210     public boolean allowsProposalEditAction(Object dataObject) {
211 
212         ProposalInfo proposalInfo = (ProposalInfo)dataObject;
213 
214         return BooleanUtils.toBoolean(proposalInfo.getAttributeValue(CAN_EDIT_PROPOSAL_KEY));
215     }
216 
217     /**
218      * Determines if given data object has associated maintenance document that allows edit maintenance
219      * actions
220      *
221      * @return boolean true if the maintenance edit action is allowed for the data object instance, false otherwise
222      */
223     public boolean allowsProposalOpenAction(Object dataObject) {
224 
225         ProposalInfo proposalInfo = (ProposalInfo)dataObject;
226 
227         return BooleanUtils.toBoolean(proposalInfo.getAttributeValue(CAN_OPEN_PROPOSAL_KEY));
228     }
229 
230     /**
231      * This is the finalizeMethodToCall which builds the action links.
232      */
233     public void buildProposalActionLink(Action actionLink, Object model, String maintenanceMethodToCall, String pageId) {
234 
235         Object dataObject = actionLink.getContext().get(UifConstants.ContextVariableNames.LINE);
236 
237         ProposalInfo proposalInfo = (ProposalInfo) dataObject;
238 
239         String href = buildHrefForActionLink(maintenanceMethodToCall, pageId, proposalInfo.getWorkflowId(), proposalInfo.getTypeKey());
240 
241         if (StringUtils.isBlank(href)) {
242             actionLink.setRender(false);
243             return;
244         }
245 
246         actionLink.setActionScript("window.open('" + href + "', '_self');");
247 
248         // rice 2.4 upgrade - commented out
249 //        lookupForm.setAtLeastOneRowHasActions(true);
250     }
251 
252     public abstract String buildHrefForActionLink(String maintenanceMethodToCall, String pageId, String workflowDocId, String proposalType);
253 
254     protected ProposalService getProposalService() {
255         if (proposalService == null) {
256             proposalService = GlobalResourceLoader.getService(new QName(ProposalServiceConstants.NAMESPACE, ProposalServiceConstants.SERVICE_NAME_LOCAL_PART));
257         }
258         return proposalService;
259     }
260 
261 }