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