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 org.kuali.rice.krms.impl.ui; 017 018import org.apache.commons.collections.CollectionUtils; 019import org.apache.commons.lang.StringUtils; 020import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException; 021import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 022import org.kuali.rice.core.api.uif.DataType; 023import org.kuali.rice.core.api.uif.RemotableAttributeField; 024import org.kuali.rice.core.api.uif.RemotableTextInput; 025import org.kuali.rice.core.api.util.tree.Node; 026import org.kuali.rice.core.api.util.tree.Tree; 027import org.kuali.rice.core.impl.cache.DistributedCacheManagerDecorator; 028import org.kuali.rice.krad.bo.PersistableBusinessObject; 029import org.kuali.rice.krad.maintenance.Maintainable; 030import org.kuali.rice.krad.maintenance.MaintainableImpl; 031import org.kuali.rice.krad.maintenance.MaintenanceDocument; 032import org.kuali.rice.krad.service.BusinessObjectService; 033import org.kuali.rice.krad.service.KRADServiceLocator; 034import org.kuali.rice.krad.service.SequenceAccessorService; 035import org.kuali.rice.krad.uif.container.CollectionGroup; 036import org.kuali.rice.krad.uif.container.Container; 037import org.kuali.rice.krad.uif.view.View; 038import org.kuali.rice.krad.util.KRADConstants; 039import org.kuali.rice.krad.util.ObjectUtils; 040import org.kuali.rice.krad.web.form.MaintenanceDocumentForm; 041import org.kuali.rice.krms.api.KrmsConstants; 042import org.kuali.rice.krms.api.repository.action.ActionDefinition; 043import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition; 044import org.kuali.rice.krms.api.repository.agenda.AgendaItemDefinition; 045import org.kuali.rice.krms.api.repository.agenda.AgendaTreeDefinition; 046import org.kuali.rice.krms.api.repository.context.ContextDefinition; 047import org.kuali.rice.krms.api.repository.function.FunctionDefinition; 048import org.kuali.rice.krms.api.repository.operator.CustomOperator; 049import org.kuali.rice.krms.api.repository.proposition.PropositionDefinition; 050import org.kuali.rice.krms.api.repository.proposition.PropositionParameterType; 051import org.kuali.rice.krms.api.repository.rule.RuleDefinition; 052import org.kuali.rice.krms.api.repository.term.TermDefinition; 053import org.kuali.rice.krms.api.repository.term.TermResolverDefinition; 054import org.kuali.rice.krms.api.repository.term.TermSpecificationDefinition; 055import org.kuali.rice.krms.api.repository.type.KrmsAttributeDefinition; 056import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition; 057import org.kuali.rice.krms.impl.repository.ActionBo; 058import org.kuali.rice.krms.impl.repository.AgendaBo; 059import org.kuali.rice.krms.impl.repository.AgendaItemBo; 060import org.kuali.rice.krms.impl.repository.ContextBoService; 061import org.kuali.rice.krms.impl.repository.KrmsAttributeDefinitionService; 062import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator; 063import org.kuali.rice.krms.impl.repository.PropositionBo; 064import org.kuali.rice.krms.impl.repository.PropositionParameterBo; 065import org.kuali.rice.krms.impl.repository.RuleBo; 066import org.kuali.rice.krms.impl.repository.TermBo; 067import org.kuali.rice.krms.impl.repository.TermParameterBo; 068import org.kuali.rice.krms.impl.util.KrmsImplConstants; 069import org.kuali.rice.krms.impl.util.KrmsRetriever; 070import org.kuali.rice.krms.impl.util.KrmsServiceLocatorInternal; 071 072import java.util.ArrayList; 073import java.util.Collections; 074import java.util.Date; 075import java.util.HashMap; 076import java.util.List; 077import java.util.Map; 078 079/** 080 * {@link Maintainable} for the {@link AgendaEditor} 081 * 082 * @author Kuali Rice Team (rice.collab@kuali.org) 083 */ 084public class AgendaEditorMaintainable extends MaintainableImpl { 085 086 private static final long serialVersionUID = 1L; 087 088 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger( 089 AgendaEditorMaintainable.class); 090 091 public static final String NEW_AGENDA_EDITOR_DOCUMENT_TEXT = "New Agenda Editor Document"; 092 093 private transient SequenceAccessorService sequenceAccessorService; 094 095 private transient KrmsRetriever krmsRetriever = new KrmsRetriever(); 096 097 /** 098 * @return the boService 099 */ 100 public BusinessObjectService getBoService() { 101 return KRADServiceLocator.getBusinessObjectService(); 102 } 103 104 /** 105 * return the contextBoService 106 */ 107 private ContextBoService getContextBoService() { 108 return KrmsRepositoryServiceLocator.getContextBoService(); 109 } 110 111 public List<RemotableAttributeField> retrieveAgendaCustomAttributes(View view, Object model, Container container) { 112 AgendaEditor agendaEditor = getAgendaEditor(model); 113 return krmsRetriever.retrieveAgendaCustomAttributes(agendaEditor); 114 } 115 116 /** 117 * Retrieve a list of {@link RemotableAttributeField}s for the parameters (if any) required by the resolver for 118 * the selected term in the proposition that is under edit. 119 */ 120 public List<RemotableAttributeField> retrieveTermParameters(View view, Object model, Container container) { 121 122 List<RemotableAttributeField> results = new ArrayList<RemotableAttributeField>(); 123 124 AgendaEditor agendaEditor = getAgendaEditor(model); 125 126 // Figure out which rule is being edited 127 RuleBo rule = agendaEditor.getAgendaItemLine().getRule(); 128 if (null != rule) { 129 130 // Figure out which proposition is being edited 131 Tree<RuleTreeNode, String> propositionTree = rule.getPropositionTree(); 132 Node<RuleTreeNode, String> editedPropositionNode = findEditedProposition(propositionTree.getRootElement()); 133 134 if (editedPropositionNode != null) { 135 PropositionBo propositionBo = editedPropositionNode.getData().getProposition(); 136 if (StringUtils.isEmpty(propositionBo.getCompoundOpCode()) && CollectionUtils.size( 137 propositionBo.getParameters()) > 0) { 138 // Get the term ID; if it is a new parameterized term, it will have a special prefix 139 PropositionParameterBo param = propositionBo.getParameters().get(0); 140 if (param.getValue().startsWith(KrmsImplConstants.PARAMETERIZED_TERM_PREFIX)) { 141 String termSpecId = param.getValue().substring( 142 KrmsImplConstants.PARAMETERIZED_TERM_PREFIX.length()); 143 TermResolverDefinition simplestResolver = getSimplestTermResolver(termSpecId, 144 rule.getNamespace()); 145 146 // Get the parameters and build RemotableAttributeFields 147 if (simplestResolver != null) { 148 List<String> parameterNames = new ArrayList<String>(simplestResolver.getParameterNames()); 149 Collections.sort(parameterNames); // make param order deterministic 150 151 for (String parameterName : parameterNames) { 152 // TODO: also allow for DD parameters if there are matching type attributes 153 RemotableTextInput.Builder controlBuilder = RemotableTextInput.Builder.create(); 154 controlBuilder.setSize(64); 155 156 RemotableAttributeField.Builder builder = RemotableAttributeField.Builder.create( 157 parameterName); 158 159 builder.setRequired(true); 160 builder.setDataType(DataType.STRING); 161 builder.setControl(controlBuilder); 162 builder.setLongLabel(parameterName); 163 builder.setShortLabel(parameterName); 164 builder.setMinLength(Integer.valueOf(1)); 165 builder.setMaxLength(Integer.valueOf(64)); 166 167 results.add(builder.build()); 168 } 169 } 170 } 171 } 172 } 173 } 174 return results; 175 } 176 177 /** 178 * finds the term resolver with the fewest parameters that resolves the given term specification 179 * 180 * @param termSpecId the id of the term specification 181 * @param namespace the namespace of the term specification 182 * @return the simples {@link TermResolverDefinition} found, or null if none was found 183 */ 184 // package access so that AgendaEditorController can use it too 185 static TermResolverDefinition getSimplestTermResolver(String termSpecId, 186 String namespace) {// Get the term resolver for the term spec 187 188 List<TermResolverDefinition> resolvers = 189 KrmsRepositoryServiceLocator.getTermBoService().findTermResolversByOutputId(termSpecId, namespace); 190 191 TermResolverDefinition simplestResolver = null; 192 193 for (TermResolverDefinition resolver : resolvers) { 194 if (simplestResolver == null || simplestResolver.getParameterNames().size() < resolver.getParameterNames() 195 .size()) { 196 simplestResolver = resolver; 197 } 198 } 199 200 return simplestResolver; 201 } 202 203 /** 204 * Find and return the node containing the proposition that is in currently in edit mode 205 * 206 * @param node the node to start searching from (typically the root) 207 * @return the node that is currently being edited, if any. Otherwise, null. 208 */ 209 private Node<RuleTreeNode, String> findEditedProposition(Node<RuleTreeNode, String> node) { 210 Node<RuleTreeNode, String> result = null; 211 if (node.getData() != null && node.getData().getProposition() != null && node.getData().getProposition() 212 .getEditMode()) { 213 result = node; 214 } else { 215 for (Node<RuleTreeNode, String> child : node.getChildren()) { 216 result = findEditedProposition(child); 217 if (result != null) { 218 break; 219 } 220 } 221 } 222 return result; 223 } 224 225 /** 226 * Get the AgendaEditor out of the MaintenanceDocumentForm's newMaintainableObject 227 * 228 * @param model the MaintenanceDocumentForm 229 * @return the AgendaEditor 230 */ 231 private AgendaEditor getAgendaEditor(Object model) { 232 MaintenanceDocumentForm maintenanceForm = (MaintenanceDocumentForm) model; 233 return (AgendaEditor) maintenanceForm.getDocument().getNewMaintainableObject().getDataObject(); 234 } 235 236 public List<RemotableAttributeField> retrieveRuleActionCustomAttributes(View view, Object model, 237 Container container) { 238 AgendaEditor agendaEditor = getAgendaEditor((MaintenanceDocumentForm) model); 239 return krmsRetriever.retrieveRuleActionCustomAttributes(agendaEditor); 240 } 241 242 /** 243 * This only supports a single action within a rule. 244 */ 245 public List<RemotableAttributeField> retrieveRuleCustomAttributes(View view, Object model, Container container) { 246 AgendaEditor agendaEditor = getAgendaEditor((MaintenanceDocumentForm) model); 247 return krmsRetriever.retrieveRuleCustomAttributes(agendaEditor); 248 } 249 250 @Override 251 public Object retrieveObjectForEditOrCopy(MaintenanceDocument document, Map<String, String> dataObjectKeys) { 252 Object dataObject = null; 253 254 try { 255 // Since the dataObject is a wrapper class we need to build it and populate with the agenda bo. 256 AgendaEditor agendaEditor = new AgendaEditor(); 257 AgendaBo agenda = getLookupService().findObjectBySearch( 258 ((AgendaEditor) getDataObject()).getAgenda().getClass(), dataObjectKeys); 259 if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(getMaintenanceAction())) { 260 String dateTimeStamp = (new Date()).getTime() + ""; 261 String newAgendaName = AgendaItemBo.COPY_OF_TEXT + agenda.getName() + " " + dateTimeStamp; 262 263 AgendaBo copiedAgenda = agenda.copyAgenda(newAgendaName, dateTimeStamp); 264 265 document.getDocumentHeader().setDocumentDescription(NEW_AGENDA_EDITOR_DOCUMENT_TEXT); 266 document.setFieldsClearedOnCopy(true); 267 agendaEditor.setAgenda(copiedAgenda); 268 } else { 269 // set custom attributes map in AgendaEditor 270 // agendaEditor.setCustomAttributesMap(agenda.getAttributes()); 271 agendaEditor.setAgenda(agenda); 272 } 273 agendaEditor.setCustomAttributesMap(agenda.getAttributes()); 274 275 // set extra fields on AgendaEditor 276 agendaEditor.setNamespace(agenda.getContext().getNamespace()); 277 agendaEditor.setContextName(agenda.getContext().getName()); 278 279 dataObject = agendaEditor; 280 } catch (ClassNotPersistenceCapableException ex) { 281 if (!document.getOldMaintainableObject().isExternalBusinessObject()) { 282 throw new RuntimeException("Data Object Class: " 283 + getDataObjectClass() 284 + " is not persistable and is not externalizable - configuration error"); 285 } 286 // otherwise, let fall through 287 } 288 289 return dataObject; 290 } 291 292 /** 293 * Returns the sequenceAssessorService 294 * 295 * @return {@link SequenceAccessorService} 296 */ 297 private SequenceAccessorService getSequenceAccessorService() { 298 if (sequenceAccessorService == null) { 299 sequenceAccessorService = KRADServiceLocator.getSequenceAccessorService(); 300 } 301 return sequenceAccessorService; 302 } 303 304 /** 305 * {@inheritDoc} 306 */ 307 @Override 308 public void processAfterNew(MaintenanceDocument document, Map<String, String[]> requestParameters) { 309 super.processAfterNew(document, requestParameters); 310 document.getDocumentHeader().setDocumentDescription(NEW_AGENDA_EDITOR_DOCUMENT_TEXT); 311 } 312 313 @Override 314 public void processAfterEdit(MaintenanceDocument document, Map<String, String[]> requestParameters) { 315 super.processAfterEdit(document, requestParameters); 316 document.getDocumentHeader().setDocumentDescription("Modify Agenda Editor Document"); 317 } 318 319 @Override 320 public void prepareForSave() { 321 // set agenda attributes 322 AgendaEditor agendaEditor = (AgendaEditor) getDataObject(); 323 agendaEditor.getAgenda().setAttributes(agendaEditor.getCustomAttributesMap()); 324 } 325 326 @Override 327 public void saveDataObject() { 328 AgendaBo agendaBo = ((AgendaEditor) getDataObject()).getAgenda(); 329 330 // handle saving new parameterized terms and processing custom operators 331 for (AgendaItemBo agendaItem : agendaBo.getItems()) { 332 PropositionBo propositionBo = agendaItem.getRule().getProposition(); 333 if (propositionBo != null) { 334 saveNewParameterizedTerms(propositionBo); 335 processCustomOperators(propositionBo); 336 } 337 } 338 339 if (agendaBo instanceof PersistableBusinessObject) { 340 Map<String, String> primaryKeys = new HashMap<String, String>(); 341 primaryKeys.put("id", agendaBo.getId()); 342 AgendaBo dbAgendaBo = getBusinessObjectService().findByPrimaryKey(AgendaBo.class, primaryKeys); 343 344 if (ObjectUtils.isNotNull(dbAgendaBo)) { 345 Map<String, String> primaryKeyForFirstItem = new HashMap<String, String>(); 346 primaryKeyForFirstItem.put("id", dbAgendaBo.getFirstItemId()); 347 AgendaItemBo dbFirstAgendaItemBo = getBusinessObjectService().findByPrimaryKey(AgendaItemBo.class, 348 primaryKeyForFirstItem); 349 350 List<AgendaItemBo> deletionOrder = new ArrayList<AgendaItemBo>(); 351 addItemsToListForDeletion(deletionOrder, dbFirstAgendaItemBo); 352 353 for (AgendaItemBo agendaItemToDelete : deletionOrder) { 354 getBusinessObjectService().delete(agendaItemToDelete); 355 } 356 357 dbAgendaBo.setItems(null); 358 getBusinessObjectService().delete(dbAgendaBo); 359 } 360 361 flushCacheBeforeSave(); 362 363 getBusinessObjectService().linkAndSave(agendaBo); 364 } else { 365 throw new RuntimeException("Cannot save object of type: " + agendaBo + " with business object service"); 366 } 367 } 368 369 370 private void addItemsToListForDeletion(List<AgendaItemBo> deletionOrder, AgendaItemBo agendaItemBo){ 371 if (!deletionOrder.contains(agendaItemBo) && ObjectUtils.isNotNull(agendaItemBo)) { 372 deletionOrder.add(agendaItemBo); 373 } 374 if (ObjectUtils.isNotNull(agendaItemBo)) { 375 if (StringUtils.isNotBlank(agendaItemBo.getWhenTrueId()) && 376 !deletionOrder.contains(agendaItemBo.getWhenTrue())) { 377 deletionOrder.add(agendaItemBo.getWhenTrue()); 378 addItemsToListForDeletion (deletionOrder, agendaItemBo.getWhenTrue()); 379 } 380 if (StringUtils.isNotBlank(agendaItemBo.getWhenFalseId()) && 381 !deletionOrder.contains(agendaItemBo.getWhenFalse())) { 382 deletionOrder.add(agendaItemBo.getWhenFalse()); 383 addItemsToListForDeletion (deletionOrder, agendaItemBo.getWhenFalse()); 384 } 385 if (StringUtils.isNotBlank(agendaItemBo.getAlwaysId()) && 386 !deletionOrder.contains(agendaItemBo.getAlways())) { 387 deletionOrder.add(agendaItemBo.getAlways()); 388 addItemsToListForDeletion (deletionOrder,agendaItemBo.getAlways()); 389 } 390 } 391 } 392 393 private void flushCacheBeforeSave(){ 394 //flush krms caches 395 DistributedCacheManagerDecorator distributedCacheManagerDecorator = 396 GlobalResourceLoader.getService(KrmsConstants.KRMS_DISTRIBUTED_CACHE); 397 398 distributedCacheManagerDecorator.getCache(ActionDefinition.Cache.NAME).clear(); 399 distributedCacheManagerDecorator.getCache(AgendaItemDefinition.Cache.NAME).clear(); 400 distributedCacheManagerDecorator.getCache(AgendaTreeDefinition.Cache.NAME).clear(); 401 distributedCacheManagerDecorator.getCache(AgendaDefinition.Cache.NAME).clear(); 402 distributedCacheManagerDecorator.getCache(ContextDefinition.Cache.NAME).clear(); 403 distributedCacheManagerDecorator.getCache(KrmsAttributeDefinition.Cache.NAME).clear(); 404 distributedCacheManagerDecorator.getCache(KrmsTypeDefinition.Cache.NAME).clear(); 405 distributedCacheManagerDecorator.getCache(RuleDefinition.Cache.NAME).clear(); 406 distributedCacheManagerDecorator.getCache(PropositionDefinition.Cache.NAME).clear(); 407 distributedCacheManagerDecorator.getCache(RuleDefinition.Cache.NAME).clear(); 408 distributedCacheManagerDecorator.getCache(TermDefinition.Cache.NAME).clear(); 409 distributedCacheManagerDecorator.getCache(TermResolverDefinition.Cache.NAME).clear(); 410 distributedCacheManagerDecorator.getCache(TermSpecificationDefinition.Cache.NAME).clear(); 411 } 412 413 /** 414 * walk the proposition tree and save any new parameterized terms that are contained therein 415 * 416 * @param propositionBo the root proposition from which to search 417 */ 418 private void saveNewParameterizedTerms(PropositionBo propositionBo) { 419 if (StringUtils.isBlank(propositionBo.getCompoundOpCode())) { 420 // it is a simple proposition 421 if (!propositionBo.getParameters().isEmpty() && propositionBo.getParameters().get(0).getValue().startsWith( 422 KrmsImplConstants.PARAMETERIZED_TERM_PREFIX)) { 423 String termId = propositionBo.getParameters().get(0).getValue(); 424 String termSpecId = termId.substring(KrmsImplConstants.PARAMETERIZED_TERM_PREFIX.length()); 425 // create new term 426 TermBo newTerm = new TermBo(); 427 newTerm.setDescription(propositionBo.getNewTermDescription()); 428 newTerm.setSpecificationId(termSpecId); 429 newTerm.setId(KRADServiceLocator.getSequenceAccessorService().getNextAvailableSequenceNumber( 430 KrmsMaintenanceConstants.Sequences.TERM_SPECIFICATION, TermBo.class).toString()); 431 432 List<TermParameterBo> params = new ArrayList<TermParameterBo>(); 433 for (Map.Entry<String, String> entry : propositionBo.getTermParameters().entrySet()) { 434 TermParameterBo param = new TermParameterBo(); 435 param.setTermId(newTerm.getId()); 436 param.setName(entry.getKey()); 437 param.setValue(entry.getValue()); 438 param.setId(KRADServiceLocator.getSequenceAccessorService().getNextAvailableSequenceNumber( 439 KrmsMaintenanceConstants.Sequences.TERM_PARAMETER, TermParameterBo.class).toString()); 440 441 params.add(param); 442 } 443 444 newTerm.setParameters(params); 445 446 KRADServiceLocator.getBusinessObjectService().linkAndSave(newTerm); 447 propositionBo.getParameters().get(0).setValue(newTerm.getId()); 448 } 449 } else { 450 // recurse 451 for (PropositionBo childProp : propositionBo.getCompoundComponents()) { 452 saveNewParameterizedTerms(childProp); 453 } 454 } 455 } 456 457 /** 458 * walk the proposition tree and process any custom operators found, converting them to custom function invocations. 459 * 460 * @param propositionBo the root proposition from which to search and convert 461 */ 462 private void processCustomOperators(PropositionBo propositionBo) { 463 if (StringUtils.isBlank(propositionBo.getCompoundOpCode())) { 464 // if it is a simple proposition with a custom operator 465 if (!propositionBo.getParameters().isEmpty() && propositionBo.getParameters().get(2).getValue().startsWith( 466 KrmsImplConstants.CUSTOM_OPERATOR_PREFIX)) { 467 PropositionParameterBo operatorParam = propositionBo.getParameters().get(2); 468 469 CustomOperator customOperator = 470 KrmsServiceLocatorInternal.getCustomOperatorUiTranslator().getCustomOperator(operatorParam.getValue()); 471 472 FunctionDefinition operatorFunctionDefinition = customOperator.getOperatorFunctionDefinition(); 473 474 operatorParam.setParameterType(PropositionParameterType.FUNCTION.getCode()); 475 operatorParam.setValue(operatorFunctionDefinition.getId()); 476 } 477 } else { 478 // recurse 479 for (PropositionBo childProp : propositionBo.getCompoundComponents()) { 480 processCustomOperators(childProp); 481 } 482 } 483 } 484 485 /** 486 * Build a map from attribute name to attribute definition from all the defined attribute definitions for the 487 * specified agenda type 488 * 489 * @param agendaTypeId 490 * @return 491 */ 492 private Map<String, KrmsAttributeDefinition> buildAttributeDefinitionMap(String agendaTypeId) { 493 KrmsAttributeDefinitionService attributeDefinitionService = 494 KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService(); 495 496 // build a map from attribute name to definition 497 Map<String, KrmsAttributeDefinition> attributeDefinitionMap = new HashMap<String, KrmsAttributeDefinition>(); 498 499 List<KrmsAttributeDefinition> attributeDefinitions = attributeDefinitionService.findAttributeDefinitionsByType( 500 agendaTypeId); 501 502 for (KrmsAttributeDefinition attributeDefinition : attributeDefinitions) { 503 attributeDefinitionMap.put(attributeDefinition.getName(), attributeDefinition); 504 } 505 return attributeDefinitionMap; 506 } 507 508 @Override 509 public boolean isOldDataObjectInDocument() { 510 boolean isOldDataObjectInExistence = true; 511 512 if (getDataObject() == null) { 513 isOldDataObjectInExistence = false; 514 } else { 515 // dataObject contains a non persistable wrapper - use agenda from the wrapper object instead 516 Map<String, ?> keyFieldValues = getDataObjectMetaDataService().getPrimaryKeyFieldValues( 517 ((AgendaEditor) getDataObject()).getAgenda()); 518 for (Object keyValue : keyFieldValues.values()) { 519 if (keyValue == null) { 520 isOldDataObjectInExistence = false; 521 } else if ((keyValue instanceof String) && StringUtils.isBlank((String) keyValue)) { 522 isOldDataObjectInExistence = false; 523 } 524 525 if (!isOldDataObjectInExistence) { 526 break; 527 } 528 } 529 } 530 531 return isOldDataObjectInExistence; 532 } 533 534 // Since the dataObject is a wrapper class we need to return the agendaBo instead. 535 @Override 536 public Class getDataObjectClass() { 537 return AgendaBo.class; 538 } 539 540 @Override 541 public boolean isLockable() { 542 return true; 543 } 544 545 @Override 546 public PersistableBusinessObject getPersistableBusinessObject() { 547 return ((AgendaEditor) getDataObject()).getAgenda(); 548 } 549 550 @Override 551 protected void processBeforeAddLine(View view, CollectionGroup collectionGroup, Object model, Object addLine) { 552 AgendaEditor agendaEditor = getAgendaEditor(model); 553 if (addLine instanceof ActionBo) { 554 ((ActionBo) addLine).setNamespace(agendaEditor.getAgendaItemLine().getRule().getNamespace()); 555 } 556 557 super.processBeforeAddLine(view, collectionGroup, model, addLine); 558 } 559}