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