Coverage Report - org.kuali.rice.kns.document.MaintenanceDocumentBase
 
Classes in this File Line Coverage Branch Coverage Complexity
MaintenanceDocumentBase
0%
0/353
0%
0/152
2.806
 
 1  
 /*
 2  
  * Copyright 2005-2007 The Kuali Foundation
 3  
  * 
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  * 
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  * 
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.kns.document;
 17  
 
 18  
 import java.io.FileNotFoundException;
 19  
 import java.io.IOException;
 20  
 import java.io.StringReader;
 21  
 import java.util.ArrayList;
 22  
 import java.util.Collections;
 23  
 import java.util.LinkedHashMap;
 24  
 import java.util.List;
 25  
 
 26  
 import javax.persistence.CascadeType;
 27  
 import javax.persistence.Column;
 28  
 import javax.persistence.Entity;
 29  
 import javax.persistence.FetchType;
 30  
 import javax.persistence.JoinColumn;
 31  
 import javax.persistence.ManyToOne;
 32  
 import javax.persistence.Table;
 33  
 import javax.persistence.Transient;
 34  
 import javax.xml.parsers.DocumentBuilder;
 35  
 import javax.xml.parsers.DocumentBuilderFactory;
 36  
 import javax.xml.parsers.ParserConfigurationException;
 37  
 
 38  
 import org.apache.commons.lang.StringUtils;
 39  
 import org.apache.ojb.broker.core.proxy.ProxyHelper;
 40  
 import org.apache.struts.upload.FormFile;
 41  
 import org.kuali.rice.core.util.RiceKeyConstants;
 42  
 import org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO;
 43  
 import org.kuali.rice.kim.bo.Person;
 44  
 import org.kuali.rice.kns.bo.BusinessObject;
 45  
 import org.kuali.rice.kns.bo.DocumentAttachment;
 46  
 import org.kuali.rice.kns.bo.DocumentHeader;
 47  
 import org.kuali.rice.kns.bo.GlobalBusinessObject;
 48  
 import org.kuali.rice.kns.bo.Note;
 49  
 import org.kuali.rice.kns.bo.PersistableAttachment;
 50  
 import org.kuali.rice.kns.bo.PersistableBusinessObject;
 51  
 import org.kuali.rice.kns.datadictionary.DocumentEntry;
 52  
 import org.kuali.rice.kns.datadictionary.WorkflowAttributes;
 53  
 import org.kuali.rice.kns.datadictionary.WorkflowProperties;
 54  
 import org.kuali.rice.kns.exception.PessimisticLockingException;
 55  
 import org.kuali.rice.kns.exception.ValidationException;
 56  
 import org.kuali.rice.kns.maintenance.Maintainable;
 57  
 import org.kuali.rice.kns.rule.event.KualiDocumentEvent;
 58  
 import org.kuali.rice.kns.rule.event.SaveDocumentEvent;
 59  
 import org.kuali.rice.kns.service.*;
 60  
 import org.kuali.rice.kns.util.GlobalVariables;
 61  
 import org.kuali.rice.kns.util.KNSConstants;
 62  
 import org.kuali.rice.kns.util.MaintenanceUtils;
 63  
 import org.kuali.rice.kns.util.NoteType;
 64  
 import org.kuali.rice.kns.util.ObjectUtils;
 65  
 import org.kuali.rice.kns.util.documentserializer.PropertySerializabilityEvaluator;
 66  
 import org.kuali.rice.kns.workflow.service.KualiWorkflowDocument;
 67  
 import org.w3c.dom.Document;
 68  
 import org.w3c.dom.Node;
 69  
 import org.w3c.dom.NodeList;
 70  
 import org.xml.sax.InputSource;
 71  
 import org.xml.sax.SAXException;
 72  
 
 73  
 
 74  
 /**
 75  
  * The maintenance xml structure will be: <maintainableDocumentContents maintainableImplClass="className">
 76  
  * <oldMaintainableObject>... </oldMaintainableObject> <newMaintainableObject>... </newMaintainableObject>
 77  
  * </maintainableDocumentContents> Maintenance Document
 78  
  */
 79  
 @Entity
 80  
 @Table(name = "KRNS_MAINT_DOC_T")
 81  
 public class MaintenanceDocumentBase extends DocumentBase implements MaintenanceDocument, SessionDocument {
 82  
     private static final long serialVersionUID = -505085142412593305L;
 83  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MaintenanceDocumentBase.class);
 84  
     public static final String MAINTAINABLE_IMPL_CLASS = "maintainableImplClass";
 85  
     public static final String OLD_MAINTAINABLE_TAG_NAME = "oldMaintainableObject";
 86  
     public static final String NEW_MAINTAINABLE_TAG_NAME = "newMaintainableObject";
 87  
     public static final String MAINTENANCE_ACTION_TAG_NAME = "maintenanceAction";
 88  
     public static final String NOTES_TAG_NAME = "notes";
 89  
 
 90  
     @Transient
 91  
     transient private static MaintenanceDocumentDictionaryService maintenanceDocumentDictionaryService;
 92  
     @Transient
 93  
     transient private static MaintenanceDocumentService maintenanceDocumentService;
 94  
     @Transient
 95  
     transient private static DocumentHeaderService documentHeaderService;
 96  
     @Transient
 97  
     transient private static DocumentService documentService;
 98  
 
 99  
     @Transient
 100  
     protected Maintainable oldMaintainableObject;
 101  
     @Transient
 102  
     protected Maintainable newMaintainableObject;
 103  
 
 104  
     @Column(name = "DOC_CNTNT", length = 4096)
 105  
     protected String xmlDocumentContents;
 106  
     @Transient
 107  
     protected boolean fieldsClearedOnCopy;
 108  0
     @Transient
 109  
     protected boolean displayTopicFieldInNotes = false;
 110  
 
 111  
     @Transient
 112  
     protected transient FormFile fileAttachment;
 113  
     @Transient
 114  
     protected String attachmentPropertyName;
 115  
 
 116  
     @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
 117  
     @JoinColumn(name = "DOC_HDR_ID", insertable = false, updatable = false)
 118  
     protected DocumentAttachment attachment;
 119  
 
 120  
     public FormFile getFileAttachment() {
 121  0
         return this.fileAttachment;
 122  
     }
 123  
 
 124  
     public void setFileAttachment(FormFile fileAttachment) {
 125  0
         this.fileAttachment = fileAttachment;
 126  0
     }
 127  
 
 128  
     public String getAttachmentPropertyName() {
 129  0
         return this.attachmentPropertyName;
 130  
     }
 131  
 
 132  
     public void setAttachmentPropertyName(String attachmentPropertyName) {
 133  0
         this.attachmentPropertyName = attachmentPropertyName;
 134  0
     }
 135  
 
 136  
     public MaintenanceDocumentBase() {
 137  0
         super();
 138  0
         fieldsClearedOnCopy = false;
 139  0
     }
 140  
 
 141  
     /**
 142  
      * Initializies the maintainables.
 143  
      */
 144  
     public MaintenanceDocumentBase(String documentTypeName) {
 145  0
         this();
 146  0
         Class clazz = getMaintenanceDocumentDictionaryService().getMaintainableClass(documentTypeName);
 147  
         try {
 148  0
             oldMaintainableObject = (Maintainable) clazz.newInstance();
 149  0
             newMaintainableObject = (Maintainable) clazz.newInstance();
 150  
 
 151  
             // initialize maintainable with a data object
 152  0
             Class<?> boClazz = getMaintenanceDocumentDictionaryService().getBusinessObjectClass(documentTypeName);
 153  0
             oldMaintainableObject.setDataObject(boClazz.newInstance());
 154  0
             oldMaintainableObject.setBoClass(boClazz);
 155  0
             newMaintainableObject.setDataObject(boClazz.newInstance());
 156  0
             newMaintainableObject.setBoClass(boClazz);
 157  
             
 158  0
         } catch (InstantiationException e) {
 159  0
             LOG.error("Unable to initialize maintainables of type " + clazz.getName());
 160  0
             throw new RuntimeException("Unable to initialize maintainables of type " + clazz.getName());
 161  0
         } catch (IllegalAccessException e) {
 162  0
             LOG.error("Unable to initialize maintainables of type " + clazz.getName());
 163  0
             throw new RuntimeException("Unable to initialize maintainables of type " + clazz.getName());
 164  0
         }
 165  0
     }
 166  
 
 167  
     /**
 168  
      * Builds out the document title for maintenance documents - this will get loaded into the flex doc and passed into workflow. It
 169  
      * will be searchable.
 170  
      */
 171  
     @Override
 172  
     public String getDocumentTitle() {
 173  0
         String documentTitle = "";
 174  
 
 175  0
         documentTitle = newMaintainableObject.getDocumentTitle(this);
 176  0
         if (StringUtils.isNotBlank(documentTitle)) {
 177  
             // if doc title has been overridden by maintainable, use it
 178  0
             return documentTitle;
 179  
         }
 180  
 
 181  
         // TODO - build out with bo label once we get the data dictionary stuff in place
 182  
         // build out the right classname
 183  0
         String className = newMaintainableObject.getDataObject().getClass().getName();
 184  0
         String truncatedClassName = className.substring(className.lastIndexOf('.') + 1);
 185  0
         if (isOldBusinessObjectInDocument()) {
 186  0
             documentTitle = "Edit ";
 187  
         } else {
 188  0
             documentTitle = "New ";
 189  
         }
 190  0
         documentTitle += truncatedClassName + " - ";
 191  0
         documentTitle += this.getDocumentHeader().getDocumentDescription() + " ";
 192  0
         return documentTitle;
 193  
     }
 194  
 
 195  
     /**
 196  
      * @param xmlDocument
 197  
      * @return
 198  
      */
 199  
     protected boolean isOldMaintainableInDocument(Document xmlDocument) {
 200  0
         boolean isOldMaintainableInExistence = false;
 201  0
         if (xmlDocument.getElementsByTagName(OLD_MAINTAINABLE_TAG_NAME).getLength() > 0) {
 202  0
             isOldMaintainableInExistence = true;
 203  
         }
 204  0
         return isOldMaintainableInExistence;
 205  
     }
 206  
 
 207  
 
 208  
     /**
 209  
      * Checks old maintainable bo has key values
 210  
      */
 211  
     public boolean isOldBusinessObjectInDocument() {
 212  0
         boolean isOldBusinessObjectInExistence = false;
 213  0
         if (oldMaintainableObject == null || oldMaintainableObject.getBusinessObject() == null) {
 214  0
             isOldBusinessObjectInExistence = false;
 215  
         } else {
 216  0
             isOldBusinessObjectInExistence = oldMaintainableObject.isOldBusinessObjectInDocument();
 217  
         }
 218  0
         return isOldBusinessObjectInExistence;
 219  
     }
 220  
 
 221  
     /**
 222  
      * This method is a simplified-naming wrapper around isOldBusinessObjectInDocument(), so that the method name matches the
 223  
      * functionality.
 224  
      */
 225  
     public boolean isNew() {
 226  0
         return MaintenanceUtils.isMaintenanceDocumentCreatingNewRecord(newMaintainableObject.getMaintenanceAction());
 227  
     }
 228  
 
 229  
     /**
 230  
      * This method is a simplified-naming wrapper around isOldBusinessObjectInDocument(), so that the method name matches the
 231  
      * functionality.
 232  
      */
 233  
     public boolean isEdit() {
 234  0
         if (KNSConstants.MAINTENANCE_EDIT_ACTION.equalsIgnoreCase(newMaintainableObject.getMaintenanceAction())) {
 235  0
             return true;
 236  
         } else {
 237  0
             return false;
 238  
         }
 239  
         // return isOldBusinessObjectInDocument();
 240  
     }
 241  
 
 242  
     public boolean isNewWithExisting() {
 243  0
         if (KNSConstants.MAINTENANCE_NEWWITHEXISTING_ACTION.equalsIgnoreCase(newMaintainableObject.getMaintenanceAction())) {
 244  0
             return true;
 245  
         } else {
 246  0
             return false;
 247  
         }
 248  
     }
 249  
 
 250  
     public void populateMaintainablesFromXmlDocumentContents() {
 251  
         // get a hold of the parsed xml document, then read the classname,
 252  
         // then instantiate one to two instances depending on content
 253  
         // then populate those instances
 254  0
         if (!StringUtils.isEmpty(xmlDocumentContents)) {
 255  0
             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
 256  
             try {
 257  0
                 DocumentBuilder builder = factory.newDocumentBuilder();
 258  0
                 Document xmlDocument = builder.parse(new InputSource(new StringReader(xmlDocumentContents)));
 259  0
                 String clazz = xmlDocument.getDocumentElement().getAttribute(MAINTAINABLE_IMPL_CLASS);
 260  0
                 if (isOldMaintainableInDocument(xmlDocument)) {
 261  0
                     oldMaintainableObject = (Maintainable) Class.forName(clazz).newInstance();
 262  0
                     Object bo = getBusinessObjectFromXML(OLD_MAINTAINABLE_TAG_NAME);
 263  
 
 264  0
                     String oldMaintenanceAction = getMaintenanceAction(xmlDocument, OLD_MAINTAINABLE_TAG_NAME);
 265  0
                     oldMaintainableObject.setMaintenanceAction(oldMaintenanceAction);
 266  
 
 267  0
                     oldMaintainableObject.setDataObject(bo);
 268  0
                     oldMaintainableObject.setBoClass(bo.getClass());
 269  
                 }
 270  0
                 newMaintainableObject = (Maintainable) Class.forName(clazz).newInstance();
 271  0
                 Object bo = getBusinessObjectFromXML(NEW_MAINTAINABLE_TAG_NAME);
 272  0
                 newMaintainableObject.setDataObject(bo);
 273  0
                 newMaintainableObject.setBoClass(bo.getClass());
 274  
 
 275  0
                 String newMaintenanceAction = getMaintenanceAction(xmlDocument, NEW_MAINTAINABLE_TAG_NAME);
 276  0
                 newMaintainableObject.setMaintenanceAction(newMaintenanceAction);
 277  
 
 278  0
                 if (newMaintainableObject.isBoNotesEnabled()) {
 279  0
                     List<Note> notes = getNotesFromXml(NOTES_TAG_NAME);
 280  0
                     setNotes(notes);
 281  
                 }
 282  
 
 283  0
             } catch (ParserConfigurationException e) {
 284  0
                 LOG.error("Error while parsing document contents", e);
 285  0
                 throw new RuntimeException("Could not load document contents from xml", e);
 286  0
             } catch (SAXException e) {
 287  0
                 LOG.error("Error while parsing document contents", e);
 288  0
                 throw new RuntimeException("Could not load document contents from xml", e);
 289  0
             } catch (IOException e) {
 290  0
                 LOG.error("Error while parsing document contents", e);
 291  0
                 throw new RuntimeException("Could not load document contents from xml", e);
 292  0
             } catch (InstantiationException e) {
 293  0
                 LOG.error("Error while parsing document contents", e);
 294  0
                 throw new RuntimeException("Could not load document contents from xml", e);
 295  0
             } catch (IllegalAccessException e) {
 296  0
                 LOG.error("Error while parsing document contents", e);
 297  0
                 throw new RuntimeException("Could not load document contents from xml", e);
 298  0
             } catch (ClassNotFoundException e) {
 299  0
                 LOG.error("Error while parsing document contents", e);
 300  0
                 throw new RuntimeException("Could not load document contents from xml", e);
 301  0
             }
 302  
 
 303  
         }
 304  0
     }
 305  
 
 306  
     /**
 307  
      * This method is a lame containment of ugly DOM walking code. This is ONLY necessary because of the version conflicts between
 308  
      * Xalan.jar in 2.6.x and 2.7. As soon as we can upgrade to 2.7, this will be switched to using XPath, which is faster and much
 309  
      * easier on the eyes.
 310  
      *
 311  
      * @param xmlDocument
 312  
      * @param oldOrNewElementName - String oldMaintainableObject or newMaintainableObject
 313  
      * @return the value of the element, or null if none was there
 314  
      */
 315  
     protected String getMaintenanceAction(Document xmlDocument, String oldOrNewElementName) {
 316  
 
 317  0
         if (StringUtils.isBlank(oldOrNewElementName)) {
 318  0
             throw new IllegalArgumentException("oldOrNewElementName may not be blank, null, or empty-string.");
 319  
         }
 320  
 
 321  0
         String maintenanceAction = null;
 322  0
         NodeList rootChildren = xmlDocument.getDocumentElement().getChildNodes();
 323  0
         for (int i = 0; i < rootChildren.getLength(); i++) {
 324  0
             Node rootChild = rootChildren.item(i);
 325  0
             if (oldOrNewElementName.equalsIgnoreCase(rootChild.getNodeName())) {
 326  0
                 NodeList maintChildren = rootChild.getChildNodes();
 327  0
                 for (int j = 0; j < maintChildren.getLength(); j++) {
 328  0
                     Node maintChild = maintChildren.item(j);
 329  0
                     if (MAINTENANCE_ACTION_TAG_NAME.equalsIgnoreCase(maintChild.getNodeName())) {
 330  0
                         maintenanceAction = maintChild.getChildNodes().item(0).getNodeValue();
 331  
                     }
 332  
                 }
 333  
             }
 334  
         }
 335  0
         return maintenanceAction;
 336  
     }
 337  
 
 338  
     private List<Note> getNotesFromXml(String notesTagName) {
 339  0
         String notesXml = StringUtils.substringBetween(xmlDocumentContents, "<" + notesTagName + ">", "</" + notesTagName + ">");
 340  0
         if (StringUtils.isBlank(notesXml)) {
 341  0
             return Collections.emptyList();
 342  
         }
 343  0
         List<Note> notes = (List<Note>) KNSServiceLocator.getXmlObjectSerializerService().fromXml(notesXml);
 344  0
         if (notes == null) {
 345  0
             return Collections.emptyList();
 346  
         }
 347  0
         return notes;
 348  
     }
 349  
 
 350  
     /**
 351  
      * Retrieves substring of document contents from maintainable tag name. Then use xml service to translate xml into a business
 352  
      * object.
 353  
      */
 354  
     protected Object getBusinessObjectFromXML(String maintainableTagName) {
 355  0
         String maintXml = StringUtils.substringBetween(xmlDocumentContents, "<" + maintainableTagName + ">", "</" + maintainableTagName + ">");
 356  0
         Object businessObject = KNSServiceLocator.getXmlObjectSerializerService().fromXml(maintXml);
 357  0
         return businessObject;
 358  
     }
 359  
 
 360  
     /**
 361  
      * Populates the xml document contents from the maintainables.
 362  
      *
 363  
      * @see org.kuali.rice.kns.document.MaintenanceDocument#populateXmlDocumentContentsFromMaintainables()
 364  
      */
 365  
     public void populateXmlDocumentContentsFromMaintainables() {
 366  0
         StringBuilder docContentBuffer = new StringBuilder();
 367  0
         docContentBuffer.append("<maintainableDocumentContents maintainableImplClass=\"").append(newMaintainableObject.getClass().getName()).append("\">");
 368  
 
 369  
         // if business objects notes are enabled then we need to persist notes to the XML
 370  0
         if (getNewMaintainableObject().isBoNotesEnabled()) {
 371  0
             docContentBuffer.append("<" + NOTES_TAG_NAME + ">");
 372  
             // copy notes to a non-ojb Proxied ArrayList to get rid of the usage of those proxies
 373  
             // note: XmlObjectSerializerServiceImpl should be doing this for us but it does not
 374  
             // appear to be working (at least in this case) and the xml comes through
 375  
             // with the fully qualified ListProxyDefault class name from OJB embedded inside it.
 376  0
             List<Note> noteList = new ArrayList<Note>();
 377  0
             for (Note note : getNotes()) {
 378  0
                 noteList.add(note);
 379  
             }
 380  0
             docContentBuffer.append(KNSServiceLocator.getXmlObjectSerializerService().toXml(noteList));
 381  0
             docContentBuffer.append("</" + NOTES_TAG_NAME + ">");
 382  
         }
 383  0
         if (oldMaintainableObject != null && oldMaintainableObject.getDataObject() != null) {
 384  
             // TODO: refactor this out into a method
 385  0
             docContentBuffer.append("<" + OLD_MAINTAINABLE_TAG_NAME + ">");
 386  
 
 387  0
             Object oldBo = oldMaintainableObject.getDataObject();
 388  
             
 389  
             // hack to resolve XStream not dealing well with Proxies
 390  0
             if(oldBo instanceof PersistableBusinessObject) {
 391  0
                 ObjectUtils.materializeAllSubObjects((PersistableBusinessObject)oldBo);
 392  
             }
 393  
             
 394  0
             docContentBuffer.append(KNSServiceLocator.getBusinessObjectSerializerService().serializeBusinessObjectToXml(oldBo));
 395  
 
 396  
             // add the maintainable's maintenanceAction
 397  0
             docContentBuffer.append("<" + MAINTENANCE_ACTION_TAG_NAME + ">");
 398  0
             docContentBuffer.append(oldMaintainableObject.getMaintenanceAction());
 399  0
             docContentBuffer.append("</" + MAINTENANCE_ACTION_TAG_NAME + ">\n");
 400  
 
 401  0
             docContentBuffer.append("</" + OLD_MAINTAINABLE_TAG_NAME + ">");
 402  
         }
 403  0
         docContentBuffer.append("<" + NEW_MAINTAINABLE_TAG_NAME + ">");
 404  
 
 405  0
         Object newBo = newMaintainableObject.getDataObject();
 406  
         
 407  0
         if(newBo instanceof PersistableBusinessObject) {
 408  
             // hack to resolve XStream not dealing well with Proxies
 409  0
             ObjectUtils.materializeAllSubObjects((PersistableBusinessObject)newBo);
 410  
         }
 411  
         
 412  0
         docContentBuffer.append(KNSServiceLocator.getBusinessObjectSerializerService().serializeBusinessObjectToXml(newBo));
 413  
 
 414  
         // add the maintainable's maintenanceAction
 415  0
         docContentBuffer.append("<" + MAINTENANCE_ACTION_TAG_NAME + ">");
 416  0
         docContentBuffer.append(newMaintainableObject.getMaintenanceAction());
 417  0
         docContentBuffer.append("</" + MAINTENANCE_ACTION_TAG_NAME + ">\n");
 418  
 
 419  0
         docContentBuffer.append("</" + NEW_MAINTAINABLE_TAG_NAME + ">");
 420  0
         docContentBuffer.append("</maintainableDocumentContents>");
 421  0
         xmlDocumentContents = docContentBuffer.toString();
 422  0
     }
 423  
 
 424  
     /**
 425  
      * @see org.kuali.rice.kns.document.DocumentBase#doRouteStatusChange(org.kuali.rice.kew.dto.DocumentRouteStatusChangeDTO)
 426  
      */
 427  
     @Override
 428  
     public void doRouteStatusChange(DocumentRouteStatusChangeDTO statusChangeEvent) {
 429  0
         super.doRouteStatusChange(statusChangeEvent);
 430  
 
 431  0
         KualiWorkflowDocument workflowDocument = getDocumentHeader().getWorkflowDocument();
 432  0
         getNewMaintainableObject().doRouteStatusChange(getDocumentHeader());
 433  
         // commit the changes to the Maintainable BusinessObject when it goes to Processed (ie, fully approved),
 434  
         // and also unlock it
 435  0
         if (workflowDocument.stateIsProcessed()) {
 436  0
             String documentNumber = getDocumentHeader().getDocumentNumber();
 437  0
             newMaintainableObject.setDocumentNumber(documentNumber);
 438  
 
 439  
             //Populate Attachment Property
 440  0
             if (newMaintainableObject.getBusinessObject() instanceof PersistableAttachment) {
 441  0
                 populateAttachmentForBO();
 442  
             }
 443  
 
 444  0
             newMaintainableObject.saveBusinessObject();
 445  
 
 446  0
             if (!getDocumentService().saveDocumentNotes(this)) {
 447  0
                 throw new IllegalStateException("Failed to save document notes, this means that the note target was not ready for notes to be attached when it should have been.");
 448  
             }
 449  
 
 450  
             //Attachment should be deleted from Maintenance Document attachment table
 451  0
             deleteDocumentAttachment();
 452  
 
 453  0
             getMaintenanceDocumentService().deleteLocks(documentNumber);
 454  
 
 455  
             //for issue 3070, check if delete record
 456  0
             if (this.checkAllowsRecordDeletion() && this.checkMaintenanceAction() &&
 457  
                     this.checkDeletePermission(newMaintainableObject.getBusinessObject()))
 458  0
                 newMaintainableObject.deleteBusinessObject();
 459  
         }
 460  
 
 461  
         // unlock the document when its canceled or disapproved
 462  0
         if (workflowDocument.stateIsCanceled() || workflowDocument.stateIsDisapproved()) {
 463  
             //Attachment should be deleted from Maintenance Document attachment table
 464  0
             deleteDocumentAttachment();
 465  
 
 466  0
             String documentNumber = getDocumentHeader().getDocumentNumber();
 467  0
             getMaintenanceDocumentService().deleteLocks(documentNumber);
 468  
         }
 469  0
     }
 470  
 
 471  
     @Override
 472  
     /**
 473  
      * @see org.kuali.rice.kns.document.DocumentBase#getWorkflowEngineDocumentIdsToLock()
 474  
      */
 475  
     public List<Long> getWorkflowEngineDocumentIdsToLock() {
 476  0
         if (newMaintainableObject != null) {
 477  0
             return newMaintainableObject.getWorkflowEngineDocumentIdsToLock();
 478  
         }
 479  0
         return Collections.emptyList();
 480  
     }
 481  
 
 482  
     /**
 483  
      * Pre-Save hook.
 484  
      *
 485  
      * @see org.kuali.rice.kns.document.Document#prepareForSave()
 486  
      */
 487  
     @Override
 488  
     public void prepareForSave() {
 489  0
         if (newMaintainableObject != null) {
 490  0
             newMaintainableObject.prepareForSave();
 491  
         }
 492  0
     }
 493  
 
 494  
     /**
 495  
      * @see org.kuali.rice.kns.document.DocumentBase#processAfterRetrieve()
 496  
      */
 497  
     @Override
 498  
     public void processAfterRetrieve() {
 499  
 
 500  0
         super.processAfterRetrieve();
 501  
             
 502  0
         populateMaintainablesFromXmlDocumentContents();
 503  0
         if (oldMaintainableObject != null) {
 504  0
             oldMaintainableObject.setDocumentNumber(documentNumber);
 505  
         }
 506  0
         if (newMaintainableObject != null) {
 507  0
             newMaintainableObject.setDocumentNumber(documentNumber);
 508  0
             newMaintainableObject.processAfterRetrieve();
 509  
             // If a maintenance lock exists, warn the user.
 510  0
             checkForLockingDocument(false);
 511  
         }
 512  
 
 513  
        
 514  
 
 515  0
     }
 516  
 
 517  
     /**
 518  
      * @return Returns the newMaintainableObject.
 519  
      */
 520  
     public Maintainable getNewMaintainableObject() {
 521  0
         return newMaintainableObject;
 522  
     }
 523  
 
 524  
     /**
 525  
      * @param newMaintainableObject The newMaintainableObject to set.
 526  
      */
 527  
     public void setNewMaintainableObject(Maintainable newMaintainableObject) {
 528  0
         this.newMaintainableObject = newMaintainableObject;
 529  0
     }
 530  
 
 531  
     /**
 532  
      * @return Returns the oldMaintainableObject.
 533  
      */
 534  
     public Maintainable getOldMaintainableObject() {
 535  0
         return oldMaintainableObject;
 536  
     }
 537  
 
 538  
     /**
 539  
      * @param oldMaintainableObject The oldMaintainableObject to set.
 540  
      */
 541  
     public void setOldMaintainableObject(Maintainable oldMaintainableObject) {
 542  0
         this.oldMaintainableObject = oldMaintainableObject;
 543  0
     }
 544  
 
 545  
     @Override
 546  
     public void setDocumentNumber(String documentNumber) {
 547  0
         super.setDocumentNumber(documentNumber);
 548  
 
 549  
         // set the finDocNumber on the Maintainable
 550  0
         oldMaintainableObject.setDocumentNumber(documentNumber);
 551  0
         newMaintainableObject.setDocumentNumber(documentNumber);
 552  
 
 553  0
     }
 554  
 
 555  
     /**
 556  
      * Gets the fieldsClearedOnCopy attribute.
 557  
      *
 558  
      * @return Returns the fieldsClearedOnCopy.
 559  
      */
 560  
     public final boolean isFieldsClearedOnCopy() {
 561  0
         return fieldsClearedOnCopy;
 562  
     }
 563  
 
 564  
     /**
 565  
      * Sets the fieldsClearedOnCopy attribute value.
 566  
      *
 567  
      * @param fieldsClearedOnCopy The fieldsClearedOnCopy to set.
 568  
      */
 569  
     public final void setFieldsClearedOnCopy(boolean fieldsClearedOnCopy) {
 570  0
         this.fieldsClearedOnCopy = fieldsClearedOnCopy;
 571  0
     }
 572  
 
 573  
     /**
 574  
      * Gets the xmlDocumentContents attribute.
 575  
      *
 576  
      * @return Returns the xmlDocumentContents.
 577  
      */
 578  
     public String getXmlDocumentContents() {
 579  0
         return xmlDocumentContents;
 580  
     }
 581  
 
 582  
     /**
 583  
      * Sets the xmlDocumentContents attribute value.
 584  
      *
 585  
      * @param xmlDocumentContents The xmlDocumentContents to set.
 586  
      */
 587  
     public void setXmlDocumentContents(String xmlDocumentContents) {
 588  0
         this.xmlDocumentContents = xmlDocumentContents;
 589  0
     }
 590  
 
 591  
     /**
 592  
      * @see org.kuali.rice.kns.document.Document#getAllowsCopy()
 593  
      */
 594  
     public boolean getAllowsCopy() {
 595  0
         return getMaintenanceDocumentDictionaryService().getAllowsCopy(this);
 596  
     }
 597  
 
 598  
     /**
 599  
      * @see org.kuali.rice.kns.document.MaintenanceDocument#getDisplayTopicFieldInNotes()
 600  
      */
 601  
     public boolean getDisplayTopicFieldInNotes() {
 602  0
         return displayTopicFieldInNotes;
 603  
     }
 604  
 
 605  
     /**
 606  
      * @see org.kuali.rice.kns.document.MaintenanceDocument#setDisplayTopicFieldInNotes(boolean)
 607  
      */
 608  
     public void setDisplayTopicFieldInNotes(boolean displayTopicFieldInNotes) {
 609  0
         this.displayTopicFieldInNotes = displayTopicFieldInNotes;
 610  0
     }
 611  
 
 612  
     @Override
 613  
     /**
 614  
      * Overridden to avoid serializing the xml twice, because of the xmlDocumentContents property of this object
 615  
      */
 616  
     public String serializeDocumentToXml() {
 617  0
         String tempXmlDocumentContents = xmlDocumentContents;
 618  0
         xmlDocumentContents = null;
 619  0
         String xmlForWorkflow = super.serializeDocumentToXml();
 620  0
         xmlDocumentContents = tempXmlDocumentContents;
 621  0
         return xmlForWorkflow;
 622  
     }
 623  
 
 624  
     @Override
 625  
     public void prepareForSave(KualiDocumentEvent event) {
 626  0
         super.prepareForSave(event);
 627  
 
 628  0
         populateDocumentAttachment();
 629  0
         populateXmlDocumentContentsFromMaintainables();
 630  0
     }
 631  
 
 632  
     /**
 633  
      * The attachment BO is proxied in OJB.  For some reason when an attachment does not yet
 634  
      * exist, refreshReferenceObject is not returning null and the proxy cannot be materialized.
 635  
      * So, this method exists to properly handle the proxied attachment BO.  This is a hack
 636  
      * and should be removed post JPA migration.
 637  
      */
 638  
     protected void refreshAttachment() {
 639  0
         if (ObjectUtils.isNull(attachment)) {
 640  0
             this.refreshReferenceObject("attachment");
 641  0
             final boolean isProxy = attachment != null && ProxyHelper.isProxy(attachment);
 642  0
             if (isProxy && ProxyHelper.getRealObject(attachment) == null) {
 643  0
                 attachment = null;
 644  
             }
 645  
         }
 646  0
     }
 647  
 
 648  
     protected void populateAttachmentForBO() {
 649  0
         refreshAttachment();
 650  
 
 651  0
         PersistableAttachment boAttachment = (PersistableAttachment) newMaintainableObject.getBusinessObject();
 652  
 
 653  0
         if (attachment != null) {
 654  
             byte[] fileContents;
 655  0
             fileContents = attachment.getAttachmentContent();
 656  0
             if (fileContents.length > 0) {
 657  0
                 boAttachment.setAttachmentContent(fileContents);
 658  0
                 boAttachment.setFileName(attachment.getFileName());
 659  0
                 boAttachment.setContentType(attachment.getContentType());
 660  
             }
 661  
         }
 662  
 
 663  0
     }
 664  
 
 665  
     public void populateDocumentAttachment() {
 666  0
         refreshAttachment();
 667  
 
 668  0
         if (fileAttachment != null && StringUtils.isNotEmpty(fileAttachment.getFileName())) {
 669  
             //Populate DocumentAttachment BO
 670  0
             if (attachment == null) {
 671  0
                 attachment = new DocumentAttachment();
 672  
             }
 673  
 
 674  
             byte[] fileContents;
 675  
             try {
 676  0
                 fileContents = fileAttachment.getFileData();
 677  0
                 if (fileContents.length > 0) {
 678  0
                     attachment.setFileName(fileAttachment.getFileName());
 679  0
                     attachment.setContentType(fileAttachment.getContentType());
 680  0
                     attachment.setAttachmentContent(fileAttachment.getFileData());
 681  0
                     attachment.setDocumentNumber(getDocumentNumber());
 682  
                 }
 683  0
             } catch (FileNotFoundException e) {
 684  0
                 LOG.error("Error while populating the Document Attachment", e);
 685  0
                 throw new RuntimeException("Could not populate DocumentAttachment object", e);
 686  0
             } catch (IOException e) {
 687  0
                 LOG.error("Error while populating the Document Attachment", e);
 688  0
                 throw new RuntimeException("Could not populate DocumentAttachment object", e);
 689  0
             }
 690  
 
 691  
         }
 692  
 //        else if(attachment != null) {
 693  
 //            //Attachment has been deleted - Need to delete the Attachment Reference Object
 694  
 //            deleteAttachment();
 695  
 //        }
 696  0
     }
 697  
 
 698  
     public void deleteDocumentAttachment() {
 699  0
         KNSServiceLocator.getBusinessObjectService().delete(attachment);
 700  0
         attachment = null;
 701  0
     }
 702  
 
 703  
     /**
 704  
      * Explicitly NOT calling super here.  This is a complete override of the validation
 705  
      * rules behavior.
 706  
      *
 707  
      * @see org.kuali.rice.kns.document.DocumentBase#validateBusinessRules(org.kuali.rice.kns.rule.event.KualiDocumentEvent)
 708  
      */
 709  
     public void validateBusinessRules(KualiDocumentEvent event) {
 710  0
         if (GlobalVariables.getMessageMap().hasErrors()) {
 711  0
             logErrors();
 712  0
             throw new ValidationException("errors occured before business rule");
 713  
         }
 714  
 
 715  
         // check for locking documents for MaintenanceDocuments
 716  0
         if (this instanceof MaintenanceDocument) {
 717  0
             checkForLockingDocument(true);
 718  
         }
 719  
 
 720  
         // Make sure the business object's version number matches that of the database's copy.
 721  0
         if (newMaintainableObject != null) {
 722  0
                 if ( KNSServiceLocator.getPersistenceStructureService().isPersistable( newMaintainableObject.getDataObject().getClass() ) ) {
 723  0
                 PersistableBusinessObject pbObject = KNSServiceLocator.getBusinessObjectService().retrieve(newMaintainableObject.getBusinessObject());
 724  0
                 Long pbObjectVerNbr = ObjectUtils.isNull(pbObject) ? null : pbObject.getVersionNumber();
 725  0
                 Long newObjectVerNbr = newMaintainableObject.getBusinessObject().getVersionNumber();
 726  0
                 if (pbObjectVerNbr != null && !(pbObjectVerNbr.equals(newObjectVerNbr))) {
 727  0
                     GlobalVariables.getMessageMap().putError(KNSConstants.GLOBAL_ERRORS, RiceKeyConstants.ERROR_VERSION_MISMATCH);
 728  0
                     throw new ValidationException("Version mismatch between the local business object and the database business object");
 729  
                 }
 730  
             }
 731  
         }
 732  
 
 733  
         // perform validation against rules engine
 734  0
         if (LOG.isInfoEnabled()) {
 735  0
             LOG.info("invoking rules engine on document " + getDocumentNumber());
 736  
         }
 737  0
         boolean isValid = true;
 738  0
         isValid = KNSServiceLocatorWeb.getKualiRuleService().applyRules(event);
 739  
 
 740  
         // check to see if the br eval passed or failed
 741  0
         if (!isValid) {
 742  0
             logErrors();
 743  
             // TODO: better error handling at the lower level and a better error message are
 744  
             // needed here
 745  0
             throw new ValidationException("business rule evaluation failed");
 746  0
         } else if (GlobalVariables.getMessageMap().hasErrors()) {
 747  0
             logErrors();
 748  0
             if (event instanceof SaveDocumentEvent) {
 749  
                 // for maintenance documents, we want to always actually do a save if the
 750  
                 // user requests a save, even if there are validation or business rules
 751  
                 // failures. this empty if does this, and allows the document to be saved,
 752  
                 // even if there are failures.
 753  
                 // BR or validation failures on a ROUTE even should always stop the route,
 754  
                 // that has not changed
 755  
             } else {
 756  0
                 throw new ValidationException("Unreported errors occured during business rule evaluation (rule developer needs to put meaningful error messages into global ErrorMap)");
 757  
             }
 758  
         }
 759  0
         LOG.debug("validation completed");
 760  
 
 761  0
     }
 762  
 
 763  
 
 764  
     protected void checkForLockingDocument(boolean throwExceptionIfLocked) {
 765  0
         MaintenanceUtils.checkForLockingDocument(this, throwExceptionIfLocked);
 766  0
     }
 767  
 
 768  
     /**
 769  
      * this needs to happen after the document itself is saved, to preserve consistency of the ver_nbr and in the case of initial
 770  
      * save, because this can't be saved until the document is saved initially
 771  
      *
 772  
      * @see org.kuali.rice.kns.document.DocumentBase#postProcessSave(org.kuali.rice.kns.rule.event.KualiDocumentEvent)
 773  
      */
 774  
     @Override
 775  
     public void postProcessSave(KualiDocumentEvent event) {
 776  0
         PersistableBusinessObject bo = getNewMaintainableObject().getBusinessObject();
 777  0
         if (bo instanceof GlobalBusinessObject) {
 778  0
             KNSServiceLocator.getBusinessObjectService().save(bo);
 779  
         }
 780  
         //currently only global documents could change the list of what they're affecting during routing,
 781  
         //so could restrict this to only happening with them, but who knows if that will change, so safest
 782  
         //to always do the delete and re-add...seems a bit inefficient though if nothing has changed, which is
 783  
         //most of the time...could also try to only add/update/delete what's changed, but this is easier
 784  0
         if (!(event instanceof SaveDocumentEvent)) { //don't lock until they route
 785  0
             getMaintenanceDocumentService().deleteLocks(this.getDocumentNumber());
 786  0
             getMaintenanceDocumentService().storeLocks(this.getNewMaintainableObject().generateMaintenanceLocks());
 787  
         }
 788  0
     }
 789  
 
 790  
     /**
 791  
      * @see org.kuali.rice.kns.document.DocumentBase#getDocumentBusinessObject()
 792  
      */
 793  
     @Override
 794  
     public PersistableBusinessObject getDocumentBusinessObject() {
 795  0
         return getNewMaintainableObject().getBusinessObject();
 796  
     }
 797  
 
 798  
     /**
 799  
      * <p>The Note target for maintenance documents is determined by whether or not the underlying
 800  
      * {@link Maintainable} supports business object notes or not.  This is determined via a call to
 801  
      * {@link Maintainable#isBoNotesEnabled()}.  The note target is then derived as follows:
 802  
      * <p/>
 803  
      * <ul>
 804  
      * <li>If the {@link Maintainable} supports business object notes, delegate to {@link #getDocumentBusinessObject()}.
 805  
      * <li>Otherwise, delegate to the default implementation of getNoteTarget on the superclass which will
 806  
      * effectively return a reference to the {@link DocumentHeader}.
 807  
      * </ul>
 808  
      *
 809  
      * @see org.kuali.rice.kns.document.Document#getNoteTarget()
 810  
      */
 811  
     @Override
 812  
     public PersistableBusinessObject getNoteTarget() {
 813  0
         if (getNewMaintainableObject() == null) {
 814  0
             throw new IllegalStateException("Failed to acquire the note target.  The new maintainable object on this document is null.");
 815  
         }
 816  0
         if (getNewMaintainableObject().isBoNotesEnabled()) {
 817  0
             return getDocumentBusinessObject();
 818  
         }
 819  0
         return super.getNoteTarget();
 820  
     }
 821  
 
 822  
     /**
 823  
      * The {@link NoteType} for maintenance documents is determined by whether or not the underlying
 824  
      * {@link Maintainable} supports business object notes or not.  This is determined via a call to
 825  
      * {@link Maintainable#isBoNotesEnabled()}.  The {@link NoteType} is then derived as follows:
 826  
      * <p/>
 827  
      * <ul>
 828  
      * <li>If the {@link Maintainable} supports business object notes, return {@link NoteType#BUSINESS_OBJECT}.
 829  
      * <li>Otherwise, delegate to {@link DocumentBase#getNoteType()}
 830  
      * </ul>
 831  
      *
 832  
      * @see org.kuali.rice.kns.document.Document#getNoteType()
 833  
      * @see org.kuali.rice.kns.document.Document#getNoteTarget()
 834  
      */
 835  
     @Override
 836  
     public NoteType getNoteType() {
 837  0
         if (getNewMaintainableObject().isBoNotesEnabled()) {
 838  0
             return NoteType.BUSINESS_OBJECT;
 839  
         }
 840  0
         return super.getNoteType();
 841  
     }
 842  
 
 843  
     @Override
 844  
     public PropertySerializabilityEvaluator getDocumentPropertySerizabilityEvaluator() {
 845  0
         String docTypeName = "";
 846  0
         if (newMaintainableObject != null) {
 847  0
             docTypeName = getMaintenanceDocumentDictionaryService().getDocumentTypeName(this.newMaintainableObject.getBoClass());
 848  
         } else { // I don't know why we aren't just using the header in the first place
 849  
             // but, in the case where we can't get it in the way above, attempt to get
 850  
             // it off the workflow document header
 851  0
             if (getDocumentHeader() != null && getDocumentHeader().getWorkflowDocument() != null) {
 852  0
                 docTypeName = getDocumentHeader().getWorkflowDocument().getDocumentType();
 853  
             }
 854  
         }
 855  0
         if (!StringUtils.isBlank(docTypeName)) {
 856  0
             DocumentEntry documentEntry = getMaintenanceDocumentDictionaryService().getMaintenanceDocumentEntry(docTypeName);
 857  0
             if (documentEntry != null) {
 858  0
                 WorkflowProperties workflowProperties = documentEntry.getWorkflowProperties();
 859  0
                 WorkflowAttributes workflowAttributes = documentEntry.getWorkflowAttributes();
 860  0
                 return createPropertySerializabilityEvaluator(workflowProperties, workflowAttributes);
 861  
             } else {
 862  0
                 LOG.error("Unable to obtain DD DocumentEntry for document type: '" + docTypeName + "'");
 863  
             }
 864  0
         } else {
 865  0
             LOG.error("Unable to obtain document type name for this document: " + this);
 866  
         }
 867  0
         LOG.error("Returning null for the PropertySerializabilityEvaluator");
 868  0
         return null;
 869  
     }
 870  
 
 871  
     public DocumentAttachment getAttachment() {
 872  0
         return this.attachment;
 873  
     }
 874  
 
 875  
     public void setAttachment(DocumentAttachment attachment) {
 876  0
         this.attachment = attachment;
 877  0
     }
 878  
 
 879  
 
 880  
     /**
 881  
      * This overridden method is used to delete the {@link DocumentHeader} object due to the system not being able to manage the {@link DocumentHeader} object via mapping files
 882  
      *
 883  
      * @see org.kuali.rice.kns.bo.PersistableBusinessObjectBase#postRemove()
 884  
      */
 885  
     @Override
 886  
     protected void postRemove() {
 887  0
         super.postRemove();
 888  0
         getDocumentHeaderService().deleteDocumentHeader(getDocumentHeader());
 889  0
     }
 890  
 
 891  
     /**
 892  
      * This overridden method is used to retrieve the {@link DocumentHeader} object due to the system not being able to manage the {@link DocumentHeader} object via mapping files
 893  
      *
 894  
      * @see org.kuali.rice.kns.bo.PersistableBusinessObjectBase#postLoad()
 895  
      */
 896  
     @Override
 897  
     protected void postLoad() {
 898  0
         super.postLoad();
 899  0
         setDocumentHeader(getDocumentHeaderService().getDocumentHeaderById(getDocumentNumber()));
 900  0
     }
 901  
 
 902  
     /**
 903  
      * This overridden method is used to insert the {@link DocumentHeader} object due to the system not being able to manage the {@link DocumentHeader} object via mapping files
 904  
      *
 905  
      * @see org.kuali.rice.kns.bo.PersistableBusinessObjectBase#prePersist()
 906  
      */
 907  
     @Override
 908  
     protected void prePersist() {
 909  0
         super.prePersist();
 910  0
         getDocumentHeaderService().saveDocumentHeader(getDocumentHeader());
 911  0
     }
 912  
 
 913  
     /**
 914  
      * This overridden method is used to save the {@link DocumentHeader} object due to the system not being able to manage the {@link DocumentHeader} object via mapping files
 915  
      *
 916  
      * @see org.kuali.rice.kns.bo.PersistableBusinessObjectBase#preUpdate()
 917  
      */
 918  
     @Override
 919  
     protected void preUpdate() {
 920  0
         super.preUpdate();
 921  0
         getDocumentHeaderService().saveDocumentHeader(getDocumentHeader());
 922  0
     }
 923  
 
 924  
     /**
 925  
      * This method to check whether the document class implements SessionDocument
 926  
      *
 927  
      * @return
 928  
      */
 929  
     public boolean isSessionDocument() {
 930  0
         return SessionDocument.class.isAssignableFrom(this.getClass());
 931  
     }
 932  
 
 933  
     /**
 934  
      * Returns whether or not the new maintainable object supports custom lock descriptors. Will always return false if the new maintainable is null.
 935  
      *
 936  
      * @see org.kuali.rice.kns.document.Document#useCustomLockDescriptors()
 937  
      * @see org.kuali.rice.kns.maintenance.Maintainable#useCustomLockDescriptors()
 938  
      */
 939  
     @Override
 940  
     public boolean useCustomLockDescriptors() {
 941  0
         return (newMaintainableObject != null && newMaintainableObject.useCustomLockDescriptors());
 942  
     }
 943  
 
 944  
     /**
 945  
      * Returns the custom lock descriptor generated by the new maintainable object, if defined. Will throw a PessimisticLockingException if
 946  
      * the new maintainable is null.
 947  
      *
 948  
      * @see org.kuali.rice.kns.document.Document#getCustomLockDescriptor(org.kuali.rice.kim.bo.Person)
 949  
      * @see org.kuali.rice.kns.maintenance.Maintainable#getCustomLockDescriptor(org.kuali.rice.kim.bo.Person)
 950  
      */
 951  
     @Override
 952  
     public String getCustomLockDescriptor(Person user) {
 953  0
         if (newMaintainableObject == null) {
 954  0
             throw new PessimisticLockingException("Maintenance Document " + getDocumentNumber() +
 955  
                     " is using pessimistic locking with custom lock descriptors, but no new maintainable object has been defined");
 956  
         }
 957  0
         return newMaintainableObject.getCustomLockDescriptor(user);
 958  
     }
 959  
 
 960  
     protected MaintenanceDocumentDictionaryService getMaintenanceDocumentDictionaryService() {
 961  0
         if (maintenanceDocumentDictionaryService == null) {
 962  0
             maintenanceDocumentDictionaryService = KNSServiceLocatorWeb.getMaintenanceDocumentDictionaryService();
 963  
         }
 964  0
         return maintenanceDocumentDictionaryService;
 965  
     }
 966  
 
 967  
     protected MaintenanceDocumentService getMaintenanceDocumentService() {
 968  0
         if (maintenanceDocumentService == null) {
 969  0
             maintenanceDocumentService = KNSServiceLocatorWeb.getMaintenanceDocumentService();
 970  
         }
 971  0
         return maintenanceDocumentService;
 972  
     }
 973  
 
 974  
     protected DocumentHeaderService getDocumentHeaderService() {
 975  0
         if (documentHeaderService == null) {
 976  0
             documentHeaderService = KNSServiceLocatorWeb.getDocumentHeaderService();
 977  
         }
 978  0
         return documentHeaderService;
 979  
     }
 980  
 
 981  
     protected DocumentService getDocumentService() {
 982  0
         if (documentService == null) {
 983  0
             documentService = KNSServiceLocatorWeb.getDocumentService();
 984  
         }
 985  0
         return documentService;
 986  
     }
 987  
 
 988  
     //for issue KULRice3070
 989  
     protected boolean checkAllowsRecordDeletion() {
 990  0
         Boolean allowsRecordDeletion = KNSServiceLocatorWeb.getMaintenanceDocumentDictionaryService().getAllowsRecordDeletion(this.getNewMaintainableObject().getBoClass());
 991  0
         if (allowsRecordDeletion != null) {
 992  0
             return allowsRecordDeletion.booleanValue();
 993  
         } else {
 994  0
             return false;
 995  
         }
 996  
     }
 997  
 
 998  
     //for KULRice3070
 999  
     protected boolean checkMaintenanceAction() {
 1000  0
         return this.getNewMaintainableObject().getMaintenanceAction().equals(KNSConstants.MAINTENANCE_DELETE_ACTION);
 1001  
     }
 1002  
 
 1003  
     //for KULRice3070
 1004  
     protected boolean checkDeletePermission(BusinessObject businessObject) {
 1005  
 
 1006  0
         boolean allowsMaintain = false;
 1007  
 
 1008  0
         String maintDocTypeName = KNSServiceLocatorWeb.getMaintenanceDocumentDictionaryService().getDocumentTypeName(businessObject.getClass());
 1009  
 
 1010  0
         if (StringUtils.isNotBlank(maintDocTypeName)) {
 1011  0
             allowsMaintain = KNSServiceLocatorWeb.getBusinessObjectAuthorizationService().canMaintain(businessObject, GlobalVariables.getUserSession().getPerson(), maintDocTypeName);
 1012  
         }
 1013  0
         return allowsMaintain;
 1014  
     }
 1015  
 }