001    /**
002     * Copyright 2005-2011 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 org.kuali.rice.krms.impl.ui;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
020    import org.kuali.rice.core.api.uif.RemotableAttributeField;
021    import org.kuali.rice.krad.bo.PersistableBusinessObject;
022    import org.kuali.rice.krad.document.MaintenanceDocument;
023    import org.kuali.rice.krad.maintenance.Maintainable;
024    import org.kuali.rice.krad.maintenance.MaintainableImpl;
025    import org.kuali.rice.krad.service.BusinessObjectService;
026    import org.kuali.rice.krad.service.KRADServiceLocator;
027    import org.kuali.rice.krad.uif.container.CollectionGroup;
028    import org.kuali.rice.krad.uif.container.Container;
029    import org.kuali.rice.krad.uif.view.View;
030    import org.kuali.rice.krad.util.KRADConstants;
031    import org.kuali.rice.krad.web.form.MaintenanceForm;
032    import org.kuali.rice.krms.api.repository.type.KrmsAttributeDefinition;
033    import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
034    import org.kuali.rice.krms.framework.type.ActionTypeService;
035    import org.kuali.rice.krms.framework.type.AgendaTypeService;
036    import org.kuali.rice.krms.framework.type.RuleTypeService;
037    import org.kuali.rice.krms.impl.repository.ActionBo;
038    import org.kuali.rice.krms.impl.repository.AgendaBo;
039    import org.kuali.rice.krms.impl.repository.ContextBoService;
040    import org.kuali.rice.krms.impl.repository.KrmsAttributeDefinitionService;
041    import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
042    import org.kuali.rice.krms.impl.type.ActionTypeServiceBase;
043    import org.kuali.rice.krms.impl.type.AgendaTypeServiceBase;
044    import org.kuali.rice.krms.impl.type.RuleTypeServiceBase;
045    
046    import java.util.ArrayList;
047    import java.util.HashMap;
048    import java.util.List;
049    import java.util.Map;
050    
051    /**
052     * {@link Maintainable} for the {@link AgendaEditor}
053     * 
054     * @author Kuali Rice Team (rice.collab@kuali.org)
055     *
056     */
057    public class AgendaEditorMaintainable extends MaintainableImpl {
058            
059            private static final long serialVersionUID = 1L;
060    
061        private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(AgendaEditorMaintainable.class);
062    
063            /**
064             * @return the boService
065             */
066            public BusinessObjectService getBoService() {
067                    return KRADServiceLocator.getBusinessObjectService();
068            }
069    
070        /**
071         * return the contextBoService
072         */
073        private ContextBoService getContextBoService() {
074            return KrmsRepositoryServiceLocator.getContextBoService();
075        }
076    
077        public List<RemotableAttributeField> retrieveCustomAttributes(View view, Object model, Container container) {
078            List<RemotableAttributeField> results = new ArrayList<RemotableAttributeField>();
079    
080            MaintenanceForm maintenanceForm = (MaintenanceForm)model;
081            AgendaEditor agendaEditor = (AgendaEditor)maintenanceForm.getDocument().getNewMaintainableObject().getDataObject();
082    
083            // if we have an agenda w/ a typeId set on it
084            if (agendaEditor.getAgenda() != null && !StringUtils.isBlank(agendaEditor.getAgenda().getTypeId())) {
085    
086                String krmsTypeId = agendaEditor.getAgenda().getTypeId();
087    
088                AgendaTypeService agendaTypeService = getAgendaTypeService(krmsTypeId);
089                results.addAll(agendaTypeService.getAttributeFields(krmsTypeId));
090            }
091    
092            return results;
093        }
094    
095        private AgendaTypeService getAgendaTypeService(String krmsTypeId) {
096            //
097            // Get the AgendaTypeService by hook or by crook
098            //
099    
100            KrmsTypeDefinition krmsType =
101                        KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService().
102                                getTypeById(krmsTypeId);
103    
104            AgendaTypeService agendaTypeService = null;
105    
106            if (!StringUtils.isBlank(krmsTypeId)) {
107                String serviceName = krmsType.getServiceName();
108    
109                if (!StringUtils.isBlank(serviceName)) {
110                    agendaTypeService = KrmsRepositoryServiceLocator.getService(serviceName);
111                }
112            }
113    
114            if (agendaTypeService == null) { agendaTypeService = AgendaTypeServiceBase.defaultAgendaTypeService; }
115    
116            return agendaTypeService;
117        }
118    
119        /**
120         *  This only supports a single action within a rule.
121         */
122        public List<RemotableAttributeField> retrieveRuleActionCustomAttributes(View view, Object model, Container container) {
123            List<RemotableAttributeField> results = new ArrayList<RemotableAttributeField>();
124    
125            MaintenanceForm maintenanceForm = (MaintenanceForm)model;
126            AgendaEditor agendaEditor = (AgendaEditor)maintenanceForm.getDocument().getNewMaintainableObject().getDataObject();
127    
128            // if we have an rule action w/ a typeId set on it
129            if (!StringUtils.isBlank(agendaEditor.getAgendaItemLineRuleAction().getTypeId())) {
130                ActionTypeService actionTypeService = getActionTypeService(agendaEditor.getAgendaItemLineRuleAction().getTypeId());
131                results.addAll(actionTypeService.getAttributeFields(agendaEditor.getAgendaItemLineRuleAction().getTypeId()));
132            }
133    
134            return results;
135        }
136    
137        public List<RemotableAttributeField> retrieveRuleCustomAttributes(View view, Object model, Container container) {
138            List<RemotableAttributeField> results = new ArrayList<RemotableAttributeField>();
139    
140            MaintenanceForm maintenanceForm = (MaintenanceForm)model;
141            AgendaEditor agendaEditor = (AgendaEditor)maintenanceForm.getDocument().getNewMaintainableObject().getDataObject();
142    
143            // if we have an rule w/ a typeId set on it
144            if (agendaEditor.getAgendaItemLine() != null && agendaEditor.getAgendaItemLine().getRule() != null
145                    && !StringUtils.isBlank(agendaEditor.getAgendaItemLine().getRule().getTypeId())) {
146    
147                String krmsTypeId = agendaEditor.getAgendaItemLine().getRule().getTypeId();
148    
149                RuleTypeService ruleTypeService = getRuleTypeService(krmsTypeId);
150                results.addAll(ruleTypeService.getAttributeFields(krmsTypeId));
151            }
152    
153            return results;
154        }
155    
156        private ActionTypeService getActionTypeService(String krmsTypeId) {
157            //
158            // Get the ActionTypeService by hook or by crook
159            //
160    
161            KrmsTypeDefinition krmsType =
162                        KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService().
163                                getTypeById(krmsTypeId);
164    
165            ActionTypeService actionTypeService = null;
166    
167            if (!StringUtils.isBlank(krmsTypeId)) {
168                String serviceName = krmsType.getServiceName();
169    
170                if (!StringUtils.isBlank(serviceName)) {
171                    actionTypeService = KrmsRepositoryServiceLocator.getService(serviceName);
172                }
173            }
174            if (actionTypeService == null) {
175                actionTypeService = ActionTypeServiceBase.defaultActionTypeService;
176            }
177    
178    //        if (actionTypeService == null) { actionTypeService = AgendaTypeServiceBase.defaultAgendaTypeService; }
179    
180            return actionTypeService;
181        }
182    
183        private RuleTypeService getRuleTypeService(String krmsTypeId) {
184            RuleTypeService ruleTypeService = null;
185            String serviceName = getRuleTypeServiceName(krmsTypeId);
186    
187            if (!StringUtils.isBlank(serviceName)) {
188                ruleTypeService = KrmsRepositoryServiceLocator.getService(serviceName);
189            }
190            if (ruleTypeService == null) {
191                ruleTypeService = RuleTypeServiceBase.defaultRuleTypeService;
192            }
193            return ruleTypeService;
194        }
195    
196        private String getRuleTypeServiceName(String krmsTypeId) {
197            String serviceName = null;
198            KrmsTypeDefinition krmsType =
199                    KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService().
200                            getTypeById(krmsTypeId);
201    
202            if (!StringUtils.isBlank(krmsTypeId)) {
203                serviceName = krmsType.getServiceName();
204            }
205            return serviceName;
206        }
207    
208        @Override
209        public Object retrieveObjectForEditOrCopy(MaintenanceDocument document, Map<String, String> dataObjectKeys) {
210            Object dataObject = null;
211    
212            try {
213                // Since the dataObject is a wrapper class we need to build it and populate with the agenda bo.
214                AgendaEditor agendaEditor = new AgendaEditor();
215                AgendaBo agenda = getLookupService().findObjectBySearch(((AgendaEditor) getDataObject()).getAgenda().getClass(), dataObjectKeys);
216                if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(getMaintenanceAction())) {
217                    // If we don't clear the primary key and set the fieldsClearedOnCopy flag then the
218                    // MaintenanceDocumentServiceImpl.processMaintenanceObjectForCopy() will try to locate the primary keys in
219                    // an attempt to clear them which again would cause an exception due to the wrapper class.
220                    agenda.setId(null);
221                    document.setFieldsClearedOnCopy(true);
222                }
223                agendaEditor.setAgenda(agenda);
224    
225                // set custom attributes map in AgendaEditor
226                agendaEditor.setCustomAttributesMap(agenda.getAttributes());
227    
228                // set extra fields on AgendaEditor
229                agendaEditor.setNamespace(agenda.getContext().getNamespace());
230                agendaEditor.setContextName(agenda.getContext().getName());
231    
232                dataObject = agendaEditor;
233            } catch (ClassNotPersistenceCapableException ex) {
234                if (!document.getOldMaintainableObject().isExternalBusinessObject()) {
235                    throw new RuntimeException("Data Object Class: " + getDataObjectClass() +
236                            " is not persistable and is not externalizable - configuration error");
237                }
238                // otherwise, let fall through
239            }
240    
241            return dataObject;
242        }
243    
244        /**
245             * {@inheritDoc}
246             */
247            @Override
248            public void processAfterNew(MaintenanceDocument document,
249                            Map<String, String[]> requestParameters) {
250    
251                    super.processAfterNew(document, requestParameters);
252            document.getDocumentHeader().setDocumentDescription("New Agenda Editor Document");
253    
254    //              if (KRADConstants.MAINTENANCE_NEW_ACTION.equals(maintenanceAction)) {
255    //                      String[] agendaIds = requestParameters.get("agendaId");
256    //                      if (agendaIds == null || agendaIds.length != 1) { 
257    //                              //throw new RiceRuntimeException("one and only one agendaId request parameter may be passed");
258    //                      } else {
259    //                              // TODO: change this, it makes more sense for MAINTENANCE_EDIT_ACTION
260    //                              String agendaId = agendaIds[0];
261    //
262    //                              AgendaBo agenda = getBoService().findBySinglePrimaryKey(AgendaBo.class, agendaId);
263    //                              String contextId = agenda.getContextId();
264    //
265    //                              ContextBo context = getBoService().findBySinglePrimaryKey(ContextBo.class, contextId);
266    //
267    //                              AgendaEditor editor = (AgendaEditor) document.getDocumentBusinessObject();
268    //
269    //                              editor.setContext(context);
270    //                              editor.setAgenda(agenda);
271    //                      }
272    //              }
273                    
274                    
275            }
276    
277        @Override
278        public void processAfterCopy(MaintenanceDocument document, Map<String, String[]> requestParameters) {
279            super.processAfterCopy(document, requestParameters);
280            document.getDocumentHeader().setDocumentDescription("New Agenda Editor Document");
281        }
282    
283        @Override
284        public void processAfterEdit(MaintenanceDocument document, Map<String, String[]> requestParameters) {
285            super.processAfterEdit(document, requestParameters);
286            document.getDocumentHeader().setDocumentDescription("Modify Agenda Editor Document");
287        }
288    
289        @Override
290        public void prepareForSave() {
291            // set agenda attributes
292            AgendaEditor agendaEditor = (AgendaEditor) getDataObject();
293            agendaEditor.getAgenda().setAttributes(agendaEditor.getCustomAttributesMap());
294        }
295    
296        @Override
297        public void saveDataObject() {
298            AgendaBo agendaBo = ((AgendaEditor) getDataObject()).getAgenda();
299            if (agendaBo instanceof PersistableBusinessObject) {
300                Map<String,String> primaryKeys = new HashMap<String, String>();
301                primaryKeys.put("id", agendaBo.getId());
302                AgendaBo blah = getBusinessObjectService().findByPrimaryKey(AgendaBo.class, primaryKeys);
303                getBusinessObjectService().delete(blah);
304    
305                getBusinessObjectService().linkAndSave(agendaBo);
306            } else {
307                throw new RuntimeException(
308                        "Cannot save object of type: " + agendaBo + " with business object service");
309            }
310        }
311    
312        /**
313         * Build a map from attribute name to attribute definition from all the defined attribute definitions for the
314         * specified agenda type
315         * @param agendaTypeId
316         * @return
317         */
318        private Map<String, KrmsAttributeDefinition> buildAttributeDefinitionMap(String agendaTypeId) {
319            KrmsAttributeDefinitionService attributeDefinitionService =
320                KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService();
321    
322            // build a map from attribute name to definition
323            Map<String, KrmsAttributeDefinition> attributeDefinitionMap = new HashMap<String, KrmsAttributeDefinition>();
324    
325            List<KrmsAttributeDefinition> attributeDefinitions =
326                    attributeDefinitionService.findAttributeDefinitionsByType(agendaTypeId);
327    
328            for (KrmsAttributeDefinition attributeDefinition : attributeDefinitions) {
329                attributeDefinitionMap.put(attributeDefinition.getName(), attributeDefinition);
330            }
331            return attributeDefinitionMap;
332        }
333    
334        @Override
335        public boolean isOldDataObjectInDocument() {
336            boolean isOldDataObjectInExistence = true;
337    
338            if (getDataObject() == null) {
339                isOldDataObjectInExistence = false;
340            } else {
341                // dataObject contains a non persistable wrapper - use agenda from the wrapper object instead
342                Map<String, ?> keyFieldValues = getDataObjectMetaDataService().getPrimaryKeyFieldValues(((AgendaEditor) getDataObject()).getAgenda());
343                for (Object keyValue : keyFieldValues.values()) {
344                    if (keyValue == null) {
345                        isOldDataObjectInExistence = false;
346                    } else if ((keyValue instanceof String) && StringUtils.isBlank((String) keyValue)) {
347                        isOldDataObjectInExistence = false;
348                    }
349    
350                    if (!isOldDataObjectInExistence) {
351                        break;
352                    }
353                }
354            }
355    
356            return isOldDataObjectInExistence;
357        }
358    
359         // Since the dataObject is a wrapper class we need to return the agendaBo instead.
360        @Override
361        public Class getDataObjectClass() {
362            return AgendaBo.class;
363        }
364    
365        @Override
366        protected void processBeforeAddLine(View view, CollectionGroup collectionGroup, Object model, Object addLine) {
367            MaintenanceForm form = (MaintenanceForm) model;
368            AgendaEditor agendaEditor = (AgendaEditor) form.getDocument().getNewMaintainableObject().getDataObject();
369            if (addLine instanceof ActionBo) {
370                ((ActionBo) addLine).setNamespace(agendaEditor.getAgendaItemLine().getRule().getNamespace());
371            }
372    
373            super.processBeforeAddLine(view, collectionGroup, model, addLine);
374        }
375    }