1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.maintenance;
17
18 import java.io.IOException;
19 import java.io.StringReader;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collections;
23 import java.util.List;
24
25 import javax.persistence.CascadeType;
26 import javax.persistence.Column;
27 import javax.persistence.Entity;
28 import javax.persistence.FetchType;
29 import javax.persistence.JoinColumn;
30 import javax.persistence.Lob;
31 import javax.persistence.ManyToOne;
32 import javax.persistence.OneToMany;
33 import javax.persistence.OneToOne;
34 import javax.persistence.Table;
35 import javax.persistence.Transient;
36 import javax.persistence.UniqueConstraint;
37 import javax.xml.parsers.DocumentBuilder;
38 import javax.xml.parsers.DocumentBuilderFactory;
39 import javax.xml.parsers.ParserConfigurationException;
40
41 import org.apache.commons.collections.CollectionUtils;
42 import org.apache.commons.lang.StringUtils;
43 import org.kuali.rice.core.api.config.property.ConfigContext;
44 import org.kuali.rice.core.api.mo.common.GloballyUnique;
45 import org.kuali.rice.kew.api.KewApiServiceLocator;
46 import org.kuali.rice.kew.api.WorkflowDocument;
47 import org.kuali.rice.kew.api.doctype.DocumentType;
48 import org.kuali.rice.kew.framework.postprocessor.DocumentRouteStatusChange;
49 import org.kuali.rice.kim.api.identity.Person;
50 import org.kuali.rice.krad.bo.DocumentAttachment;
51 import org.kuali.rice.krad.bo.DocumentHeader;
52 import org.kuali.rice.krad.bo.MultiDocumentAttachment;
53 import org.kuali.rice.krad.bo.Note;
54 import org.kuali.rice.krad.bo.PersistableAttachment;
55 import org.kuali.rice.krad.bo.PersistableAttachmentList;
56 import org.kuali.rice.krad.data.KradDataServiceLocator;
57 import org.kuali.rice.krad.datadictionary.DocumentEntry;
58 import org.kuali.rice.krad.datadictionary.WorkflowAttributes;
59 import org.kuali.rice.krad.datadictionary.WorkflowProperties;
60 import org.kuali.rice.krad.document.DocumentBase;
61 import org.kuali.rice.krad.document.SessionDocument;
62 import org.kuali.rice.krad.exception.PessimisticLockingException;
63 import org.kuali.rice.krad.exception.ValidationException;
64 import org.kuali.rice.krad.rules.rule.event.DocumentEvent;
65 import org.kuali.rice.krad.rules.rule.event.SaveDocumentEvent;
66 import org.kuali.rice.krad.service.BusinessObjectSerializerService;
67 import org.kuali.rice.krad.service.DocumentDictionaryService;
68 import org.kuali.rice.krad.service.DocumentService;
69 import org.kuali.rice.krad.service.KRADServiceLocator;
70 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
71 import org.kuali.rice.krad.service.MaintenanceDocumentService;
72 import org.kuali.rice.krad.util.GlobalVariables;
73 import org.kuali.rice.krad.util.KRADConstants;
74 import org.kuali.rice.krad.util.NoteType;
75 import org.kuali.rice.krad.util.documentserializer.PropertySerializabilityEvaluator;
76 import org.w3c.dom.Document;
77 import org.w3c.dom.Node;
78 import org.w3c.dom.NodeList;
79 import org.xml.sax.InputSource;
80 import org.xml.sax.SAXException;
81
82 import com.thoughtworks.xstream.core.BaseException;
83
84
85
86
87
88
89
90
91
92
93
94
95
96 @Entity
97 @Table(name = "KRNS_MAINT_DOC_T",uniqueConstraints= {
98 @UniqueConstraint(name="KRNS_MAINT_DOC_TC0",columnNames="OBJ_ID")
99 })
100 public class MaintenanceDocumentBase extends DocumentBase implements MaintenanceDocument, SessionDocument {
101 protected static final int SUB_OBJECT_MATERIALIZATION_DEPTH = 3;
102 private static final long serialVersionUID = -505085142412593305L;
103 private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(MaintenanceDocumentBase.class);
104
105 public static final String MAINTAINABLE_IMPL_CLASS = "maintainableImplClass";
106 public static final String OLD_MAINTAINABLE_TAG_NAME = "oldMaintainableObject";
107 public static final String NEW_MAINTAINABLE_TAG_NAME = "newMaintainableObject";
108 public static final String MAINTENANCE_ACTION_TAG_NAME = "maintenanceAction";
109 public static final String NOTES_TAG_NAME = "notes";
110
111 @Transient
112 private static transient DocumentDictionaryService documentDictionaryService;
113 @Transient
114 private static transient MaintenanceDocumentService maintenanceDocumentService;
115 @Transient
116 private static transient DocumentService documentService;
117
118 @Transient
119 protected Maintainable oldMaintainableObject;
120
121 @Transient
122 protected Maintainable newMaintainableObject;
123
124 @Lob
125 @Column(name = "DOC_CNTNT")
126 protected String xmlDocumentContents;
127 @Transient
128 protected boolean fieldsClearedOnCopy;
129 @Transient
130 protected boolean displayTopicFieldInNotes = false;
131 @Transient
132 protected String attachmentPropertyName;
133 @Transient
134 protected String attachmentListPropertyName;
135 @Transient
136 protected String attachmentCollectionName;
137
138 @OneToOne(fetch = FetchType.LAZY,
139 cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
140 @JoinColumn(name = "DOC_HDR_ID",
141 insertable = false, updatable = false)
142 protected DocumentAttachment attachment;
143
144 @OneToMany(fetch = FetchType.LAZY,
145 cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
146 @JoinColumn(name = "DOC_HDR_ID",
147 insertable = false, updatable = false)
148 protected List<MultiDocumentAttachment> attachments;
149
150 public MaintenanceDocumentBase() {
151 super();
152 fieldsClearedOnCopy = false;
153 }
154
155
156
157
158 public MaintenanceDocumentBase(String documentTypeName) {
159 this();
160 Class clazz = getDocumentDictionaryService().getMaintainableClass(documentTypeName);
161 try {
162 oldMaintainableObject = (Maintainable) clazz.newInstance();
163 newMaintainableObject = (Maintainable) clazz.newInstance();
164
165
166 Class<?> dataObjectClazz = getDocumentDictionaryService().getMaintenanceDataObjectClass(documentTypeName);
167 oldMaintainableObject.setDataObject(dataObjectClazz.newInstance());
168 oldMaintainableObject.setDataObjectClass(dataObjectClazz);
169 newMaintainableObject.setDataObject(dataObjectClazz.newInstance());
170 newMaintainableObject.setDataObjectClass(dataObjectClazz);
171 } catch (InstantiationException e) {
172 LOG.error("Unable to initialize maintainables of type " + clazz.getName());
173 throw new RuntimeException("Unable to initialize maintainables of type " + clazz.getName());
174 } catch (IllegalAccessException e) {
175 LOG.error("Unable to initialize maintainables of type " + clazz.getName());
176 throw new RuntimeException("Unable to initialize maintainables of type " + clazz.getName());
177 }
178 }
179
180
181
182
183
184
185
186
187
188
189 @Override
190 public String getDocumentTitle() {
191 String documentTitle = "";
192
193 documentTitle = newMaintainableObject.getDocumentTitle(this);
194 if (StringUtils.isNotBlank(documentTitle)) {
195
196 return documentTitle;
197 }
198
199
200
201 String className = newMaintainableObject.getDataObject().getClass().getName();
202 String truncatedClassName = className.substring(className.lastIndexOf('.') + 1);
203 if (isOldDataObjectInDocument()) {
204 if (KRADConstants.MAINTENANCE_COPY_ACTION.equals(oldMaintainableObject.getMaintenanceAction())) {
205 documentTitle = "Copy ";
206 } else {
207 documentTitle = "Edit ";
208 }
209 } else {
210 documentTitle = "New ";
211 }
212 documentTitle += truncatedClassName + " - ";
213 documentTitle += this.getDocumentHeader().getDocumentDescription() + " ";
214 return documentTitle;
215 }
216
217
218
219
220
221
222
223 protected boolean isOldMaintainableInDocument(Document xmlDocument) {
224 boolean isOldMaintainableInExistence = false;
225 if (xmlDocument.getElementsByTagName(OLD_MAINTAINABLE_TAG_NAME).getLength() > 0) {
226 isOldMaintainableInExistence = true;
227 }
228 return isOldMaintainableInExistence;
229 }
230
231
232
233
234 @Override
235 public boolean isOldDataObjectInDocument() {
236 boolean isOldBusinessObjectInExistence = false;
237 if (oldMaintainableObject == null || oldMaintainableObject.getDataObject() == null) {
238 isOldBusinessObjectInExistence = false;
239 } else {
240 isOldBusinessObjectInExistence = oldMaintainableObject.isOldDataObjectInDocument();
241 }
242 return isOldBusinessObjectInExistence;
243 }
244
245
246
247
248 @Override
249 public boolean isNew() {
250 return MaintenanceUtils.isMaintenanceDocumentCreatingNewRecord(newMaintainableObject.getMaintenanceAction());
251 }
252
253
254
255
256 @Override
257 public boolean isEdit() {
258 if (KRADConstants.MAINTENANCE_EDIT_ACTION.equalsIgnoreCase(newMaintainableObject.getMaintenanceAction())) {
259 return true;
260 } else {
261 return false;
262 }
263 }
264
265
266
267
268 @Override
269 public boolean isNewWithExisting() {
270 if (KRADConstants.MAINTENANCE_NEWWITHEXISTING_ACTION.equalsIgnoreCase(
271 newMaintainableObject.getMaintenanceAction())) {
272 return true;
273 } else {
274 return false;
275 }
276 }
277
278
279
280
281 @Override
282 public void populateMaintainablesFromXmlDocumentContents() {
283
284
285
286 if (!StringUtils.isEmpty(xmlDocumentContents)) {
287 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
288
289
290
291
292
293
294
295 try {
296 DocumentBuilder builder = factory.newDocumentBuilder();
297 Document xmlDocument = builder.parse(new InputSource(new StringReader(xmlDocumentContents)));
298 String documentTypeName = KewApiServiceLocator.getWorkflowDocumentService().getDocument(this.getDocumentNumber()).getDocumentTypeName();
299 Class<? extends Maintainable> maintainableClass = getDocumentDictionaryService().getMaintainableClass(documentTypeName);
300 if (isOldMaintainableInDocument(xmlDocument)) {
301 oldMaintainableObject = (Maintainable) maintainableClass.newInstance();
302 Object dataObject = getDataObjectFromXML(OLD_MAINTAINABLE_TAG_NAME);
303
304 String oldMaintenanceAction = getMaintenanceAction(xmlDocument, OLD_MAINTAINABLE_TAG_NAME);
305 oldMaintainableObject.setMaintenanceAction(oldMaintenanceAction);
306
307 oldMaintainableObject.setDataObject(dataObject);
308 oldMaintainableObject.setDataObjectClass(dataObject.getClass());
309 }
310 newMaintainableObject = (Maintainable) maintainableClass.newInstance();
311 Object bo = getDataObjectFromXML(NEW_MAINTAINABLE_TAG_NAME);
312 newMaintainableObject.setDataObject(bo);
313 newMaintainableObject.setDataObjectClass(bo.getClass());
314
315 String newMaintenanceAction = getMaintenanceAction(xmlDocument, NEW_MAINTAINABLE_TAG_NAME);
316 newMaintainableObject.setMaintenanceAction(newMaintenanceAction);
317
318 if (newMaintainableObject.isNotesEnabled()) {
319 List<Note> notes = getNotesFromXml(NOTES_TAG_NAME);
320 setNotes(notes);
321 }
322 } catch (ParserConfigurationException e) {
323 LOG.error("Error while parsing document contents", e);
324 throw new RuntimeException("Could not load document contents from xml", e);
325 } catch (SAXException e) {
326 LOG.error("Error while parsing document contents", e);
327 throw new RuntimeException("Could not load document contents from xml", e);
328 } catch (IOException e) {
329 LOG.error("Error while parsing document contents", e);
330 throw new RuntimeException("Could not load document contents from xml", e);
331 } catch (InstantiationException e) {
332 LOG.error("Error while parsing document contents", e);
333 throw new RuntimeException("Could not load document contents from xml", e);
334 } catch (IllegalAccessException e) {
335 LOG.error("Error while parsing document contents", e);
336 throw new RuntimeException("Could not load document contents from xml", e);
337 }
338 }
339 }
340
341
342
343
344
345
346
347
348
349
350 protected String getMaintenanceAction(Document xmlDocument, String oldOrNewElementName) {
351 if (StringUtils.isBlank(oldOrNewElementName)) {
352 throw new IllegalArgumentException("oldOrNewElementName may not be blank, null, or empty-string.");
353 }
354
355 String maintenanceAction = null;
356 NodeList rootChildren = xmlDocument.getDocumentElement().getChildNodes();
357 for (int i = 0; i < rootChildren.getLength(); i++) {
358 Node rootChild = rootChildren.item(i);
359 if (oldOrNewElementName.equalsIgnoreCase(rootChild.getNodeName())) {
360 NodeList maintChildren = rootChild.getChildNodes();
361 for (int j = 0; j < maintChildren.getLength(); j++) {
362 Node maintChild = maintChildren.item(j);
363 if (MAINTENANCE_ACTION_TAG_NAME.equalsIgnoreCase(maintChild.getNodeName())) {
364 maintenanceAction = maintChild.getChildNodes().item(0).getNodeValue();
365 }
366 }
367 }
368 }
369 return maintenanceAction;
370 }
371
372
373
374
375
376
377
378 private List<Note> getNotesFromXml(String notesTagName) {
379 String notesXml = StringUtils.substringBetween(xmlDocumentContents, "<" + notesTagName + ">",
380 "</" + notesTagName + ">");
381 if (StringUtils.isBlank(notesXml)) {
382 return Collections.emptyList();
383 }
384 List<Note> notes = (List<Note>) KRADServiceLocator.getXmlObjectSerializerService().fromXml(notesXml);
385 if (notes == null) {
386 return Collections.emptyList();
387 }
388 return notes;
389 }
390
391
392
393
394
395
396
397
398
399
400
401
402 protected Object getDataObjectFromXML(String maintainableTagName) {
403 String maintXml = StringUtils.substringBetween(xmlDocumentContents, "<" + maintainableTagName + ">",
404 "</" + maintainableTagName + ">");
405
406 try {
407 boolean ignoreMissingFields = false;
408 String classAndDocTypeNames = ConfigContext.getCurrentContextConfig().getProperty(KRADConstants.Config.IGNORE_MISSIONG_FIELDS_ON_DESERIALIZE);
409 if (!StringUtils.isEmpty(classAndDocTypeNames)) {
410 String classNameOnXML = StringUtils.substringBetween(xmlDocumentContents, "<" + maintainableTagName + "><", ">");
411 String classNamesNoSpaces = removeSpacesAround(classAndDocTypeNames);
412 List<String> classAndDocTypeNamesList = Arrays.asList(org.apache.commons.lang.StringUtils.split(classNamesNoSpaces, ","));
413 String originalDocTypeId = getDocumentHeader().getWorkflowDocument().getDocumentTypeId();
414 DocumentType docType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeById(originalDocTypeId);
415
416 while (docType != null && !ignoreMissingFields) {
417 for(String classNameOrDocTypeName : classAndDocTypeNamesList){
418 if (docType.getName().equalsIgnoreCase(classNameOrDocTypeName) ||
419 classNameOnXML.equalsIgnoreCase(classNameOrDocTypeName)) {
420 ignoreMissingFields = true;
421 break;
422 }
423 }
424 if (!StringUtils.isEmpty(docType.getParentId())) {
425 docType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeById(docType.getParentId());
426 } else {
427 docType = null;
428 }
429 }
430 }
431 if (!ignoreMissingFields) {
432 return KRADServiceLocator.getXmlObjectSerializerService().fromXml(maintXml);
433 } else {
434 return KRADServiceLocator.getXmlObjectSerializerIgnoreMissingFieldsService().fromXml(maintXml);
435 }
436 }catch (BaseException e) {
437 String convertedXml = KRADServiceLocatorWeb.getMaintainableXMLConversionService().transformMaintainableXML(maintXml);
438 return KRADServiceLocator.getXmlObjectSerializerService().fromXml(convertedXml);
439 }
440 }
441
442
443
444
445
446
447
448
449
450
451 private String removeSpacesAround(String csv) {
452 if (csv == null) {
453 return null;
454 }
455
456 final StringBuilder result = new StringBuilder();
457 for (final String value : csv.split(",")) {
458 if (!"".equals(value.trim())) {
459 result.append(value.trim());
460 result.append(",");
461 }
462 }
463
464
465 int i = result.lastIndexOf(",");
466 if (i != -1) {
467 result.deleteCharAt(i);
468 }
469
470 return result.toString();
471 }
472
473
474
475
476
477
478 @Override
479 public void populateXmlDocumentContentsFromMaintainables() {
480 StringBuilder docContentBuffer = new StringBuilder();
481 docContentBuffer.append("<maintainableDocumentContents maintainableImplClass=\"").append(
482 newMaintainableObject.getClass().getName()).append("\">");
483
484
485 if (getNewMaintainableObject().isNotesEnabled()) {
486 docContentBuffer.append("<" + NOTES_TAG_NAME + ">");
487
488
489
490
491 List<Note> noteList = new ArrayList<Note>();
492 for (Note note : getNotes()) {
493 noteList.add(note);
494 }
495 docContentBuffer.append(KRADServiceLocator.getXmlObjectSerializerService().toXml(noteList));
496 docContentBuffer.append("</" + NOTES_TAG_NAME + ">");
497 }
498 if (oldMaintainableObject != null && oldMaintainableObject.getDataObject() != null) {
499
500 docContentBuffer.append("<" + OLD_MAINTAINABLE_TAG_NAME + ">");
501
502 Object oldBo = oldMaintainableObject.getDataObject();
503
504
505
506 KRADServiceLocatorWeb.getLegacyDataAdapter().materializeAllSubObjects(oldBo);
507
508 docContentBuffer.append(getBusinessObjectSerializerService().serializeBusinessObjectToXml(oldBo));
509
510
511 docContentBuffer.append("<" + MAINTENANCE_ACTION_TAG_NAME + ">");
512 docContentBuffer.append(oldMaintainableObject.getMaintenanceAction());
513 docContentBuffer.append("</" + MAINTENANCE_ACTION_TAG_NAME + ">\n");
514
515 docContentBuffer.append("</" + OLD_MAINTAINABLE_TAG_NAME + ">");
516 }
517 docContentBuffer.append("<" + NEW_MAINTAINABLE_TAG_NAME + ">");
518
519 Object newBo = newMaintainableObject.getDataObject();
520
521
522 KRADServiceLocatorWeb.getLegacyDataAdapter().materializeAllSubObjects(newBo);
523
524 docContentBuffer.append(getBusinessObjectSerializerService().serializeBusinessObjectToXml(newBo));
525
526
527 docContentBuffer.append("<" + MAINTENANCE_ACTION_TAG_NAME + ">");
528 docContentBuffer.append(newMaintainableObject.getMaintenanceAction());
529 docContentBuffer.append("</" + MAINTENANCE_ACTION_TAG_NAME + ">\n");
530
531 docContentBuffer.append("</" + NEW_MAINTAINABLE_TAG_NAME + ">");
532 docContentBuffer.append("</maintainableDocumentContents>");
533 xmlDocumentContents = docContentBuffer.toString();
534 }
535
536
537
538
539 @Override
540 public void doRouteStatusChange(DocumentRouteStatusChange statusChangeEvent) {
541 super.doRouteStatusChange(statusChangeEvent);
542
543 WorkflowDocument workflowDocument = getDocumentHeader().getWorkflowDocument();
544 getNewMaintainableObject().doRouteStatusChange(getDocumentHeader());
545
546
547 if (workflowDocument.isProcessed()) {
548 final String documentNumber = getDocumentHeader().getDocumentNumber();
549 newMaintainableObject.setDocumentNumber(documentNumber);
550
551
552 if (newMaintainableObject.getDataObject() instanceof PersistableAttachment) {
553 populateAttachmentBeforeSave();
554 }
555
556
557 if (newMaintainableObject.getDataObject() instanceof PersistableAttachmentList) {
558 populateBoAttachmentListBeforeSave();
559 }
560
561 newMaintainableObject.saveDataObject();
562
563 if (!getDocumentService().saveDocumentNotes(this)) {
564 throw new IllegalStateException(
565 "Failed to save document notes, this means that the note target was not ready for notes to be attached when it should have been.");
566 }
567
568
569 deleteDocumentAttachment();
570 deleteDocumentAttachmentList();
571
572 getMaintenanceDocumentService().deleteLocks(documentNumber);
573
574
575 if (this.checkAllowsRecordDeletion() && this.checkMaintenanceAction() &&
576 this.checkDeletePermission(newMaintainableObject.getDataObject())) {
577 newMaintainableObject.deleteDataObject();
578 }
579 }
580
581
582 if (workflowDocument.isCanceled() || workflowDocument.isDisapproved() || workflowDocument.isRecalled() || workflowDocument.isException()) {
583
584 deleteDocumentAttachment();
585 deleteDocumentAttachmentList();
586
587 String documentNumber = getDocumentHeader().getDocumentNumber();
588 getMaintenanceDocumentService().deleteLocks(documentNumber);
589 }
590 }
591
592
593
594
595 @Override
596 public List<String> getWorkflowEngineDocumentIdsToLock() {
597 if (newMaintainableObject != null) {
598 return newMaintainableObject.getWorkflowEngineDocumentIdsToLock();
599 }
600 return Collections.emptyList();
601 }
602
603
604
605
606 @Override
607 public void prepareForSave() {
608 if (newMaintainableObject != null) {
609 newMaintainableObject.prepareForSave();
610 }
611 }
612
613
614
615
616 @Override
617 public void processAfterRetrieve() {
618
619 super.processAfterRetrieve();
620
621 populateMaintainablesFromXmlDocumentContents();
622 if (oldMaintainableObject != null) {
623 oldMaintainableObject.setDocumentNumber(documentNumber);
624 }
625 if (newMaintainableObject != null) {
626 newMaintainableObject.setDocumentNumber(documentNumber);
627 newMaintainableObject.processAfterRetrieve();
628 if (newMaintainableObject.getDataObject() instanceof PersistableAttachment) {
629 populateAttachmentForBO();
630 }
631 if (newMaintainableObject.getDataObject() instanceof PersistableAttachmentList) {
632 populateAttachmentListForBO();
633 }
634
635 checkForLockingDocument(false);
636 }
637 }
638
639
640
641
642 @Override
643 public Maintainable getNewMaintainableObject() {
644 return newMaintainableObject;
645 }
646
647
648
649
650 @Override
651 public void setNewMaintainableObject(Maintainable newMaintainableObject) {
652 this.newMaintainableObject = newMaintainableObject;
653 }
654
655
656
657
658 @Override
659 public Maintainable getOldMaintainableObject() {
660 return oldMaintainableObject;
661 }
662
663
664
665
666 @Override
667 public void setOldMaintainableObject(Maintainable oldMaintainableObject) {
668 this.oldMaintainableObject = oldMaintainableObject;
669 }
670
671
672
673
674 @Override
675 public void setDocumentNumber(String documentNumber) {
676 super.setDocumentNumber(documentNumber);
677
678
679 oldMaintainableObject.setDocumentNumber(documentNumber);
680 newMaintainableObject.setDocumentNumber(documentNumber);
681 }
682
683
684
685
686 @Override
687 public final boolean isFieldsClearedOnCopy() {
688 return fieldsClearedOnCopy;
689 }
690
691
692
693
694 @Override
695 public final void setFieldsClearedOnCopy(boolean fieldsClearedOnCopy) {
696 this.fieldsClearedOnCopy = fieldsClearedOnCopy;
697 }
698
699
700
701
702 @Override
703 public String getXmlDocumentContents() {
704 return xmlDocumentContents;
705 }
706
707
708
709
710 @Override
711 public void setXmlDocumentContents(String xmlDocumentContents) {
712 this.xmlDocumentContents = xmlDocumentContents;
713 }
714
715
716
717
718 @Override
719 public boolean getAllowsCopy() {
720 return getDocumentDictionaryService().getAllowsCopy(this);
721 }
722
723
724
725
726 @Override
727 public boolean isDisplayTopicFieldInNotes() {
728 return displayTopicFieldInNotes;
729 }
730
731
732
733
734 @Override
735 public void setDisplayTopicFieldInNotes(boolean displayTopicFieldInNotes) {
736 this.displayTopicFieldInNotes = displayTopicFieldInNotes;
737 }
738
739
740
741
742 @Override
743 public String serializeDocumentToXml() {
744 String tempXmlDocumentContents = xmlDocumentContents;
745 xmlDocumentContents = null;
746 String xmlForWorkflow = super.serializeDocumentToXml();
747 xmlDocumentContents = tempXmlDocumentContents;
748 return xmlForWorkflow;
749 }
750
751
752
753
754 @Override
755 public void prepareForSave(DocumentEvent event) {
756 super.prepareForSave(event);
757 if (newMaintainableObject.getDataObject() instanceof PersistableAttachment) {
758 populateDocumentAttachment();
759 populateAttachmentForBO();
760
761 if (oldMaintainableObject.getDataObject() instanceof PersistableAttachment) {
762 ((PersistableAttachment) oldMaintainableObject.getDataObject()).setAttachmentContent(null);
763 }
764 }
765 if (newMaintainableObject.getDataObject() instanceof PersistableAttachmentList) {
766 populateDocumentAttachmentList();
767 populateAttachmentListForBO();
768 if (oldMaintainableObject.getDataObject() instanceof PersistableAttachmentList) {
769 for (PersistableAttachment pa : ((PersistableAttachmentList<PersistableAttachment>) oldMaintainableObject
770 .getDataObject()).getAttachments()) {
771 pa.setAttachmentContent(null);
772 }
773 }
774 }
775 populateXmlDocumentContentsFromMaintainables();
776 }
777
778
779
780
781
782
783 @Deprecated
784 protected void refreshAttachment() {
785 if (attachment == null) {
786 KradDataServiceLocator.getDataObjectService().wrap(this).fetchRelationship("attachment");
787 }
788 }
789
790 @Deprecated
791 protected void refreshAttachmentList() {
792 if (attachments == null) {
793 KradDataServiceLocator.getDataObjectService().wrap(this).fetchRelationship("attachments");
794 }
795 }
796
797 @Deprecated
798 public void populateAttachmentForBO() { }
799
800 @Deprecated
801 public void populateDocumentAttachment() { }
802
803 @Deprecated
804 public void populateAttachmentListForBO() { }
805
806 @Deprecated
807 public void populateAttachmentBeforeSave() { }
808
809 @Deprecated
810 public void populateDocumentAttachmentList() { }
811
812 @Deprecated
813 public void populateBoAttachmentListBeforeSave() { }
814
815 @Deprecated
816 public void deleteDocumentAttachment() {
817 if ( attachment != null ) {
818 KRADServiceLocatorWeb.getLegacyDataAdapter().delete(attachment);
819 attachment = null;
820 }
821 }
822
823 @Deprecated
824 public void deleteDocumentAttachmentList() {
825 if (CollectionUtils.isNotEmpty(attachments)) {
826 for (MultiDocumentAttachment attachment : attachments) {
827 KRADServiceLocatorWeb.getLegacyDataAdapter().delete(attachment);
828 }
829 attachments = null;
830 }
831 }
832
833
834
835
836
837
838 @Override
839 public void validateBusinessRules(DocumentEvent event) {
840 if (GlobalVariables.getMessageMap().hasErrors()) {
841 logErrors();
842 throw new ValidationException("errors occured before business rule");
843 }
844
845
846 checkForLockingDocument(true);
847
848
849
850 if (newMaintainableObject != null) {
851 KRADServiceLocatorWeb.getLegacyDataAdapter().verifyVersionNumber(newMaintainableObject.getDataObject());
852 }
853
854
855 if (LOG.isInfoEnabled()) {
856 LOG.info("invoking rules engine on document " + getDocumentNumber());
857 }
858
859 boolean isValid = true;
860 isValid = KRADServiceLocatorWeb.getKualiRuleService().applyRules(event);
861
862
863 if (!isValid) {
864 logErrors();
865
866
867 throw new ValidationException("business rule evaluation failed");
868 } else if (GlobalVariables.getMessageMap().hasErrors()) {
869 logErrors();
870 if (event instanceof SaveDocumentEvent) {
871
872
873
874
875
876
877 } else {
878 throw new ValidationException(
879 "Unreported errors occurred during business rule evaluation (rule developer needs to put meaningful error messages into global ErrorMap)");
880 }
881 }
882
883 LOG.debug("validation completed");
884 }
885
886 protected void checkForLockingDocument(boolean throwExceptionIfLocked) {
887 MaintenanceUtils.checkForLockingDocument(this, throwExceptionIfLocked);
888 }
889
890
891
892
893
894
895
896 @Override
897 public void postProcessSave(DocumentEvent event) {
898
899
900
901
902 if (!(event instanceof SaveDocumentEvent)) {
903 getMaintenanceDocumentService().deleteLocks(MaintenanceDocumentBase.this.getDocumentNumber());
904 getMaintenanceDocumentService().storeLocks(MaintenanceDocumentBase.this.getNewMaintainableObject().generateMaintenanceLocks());
905 }
906 }
907
908
909
910
911 @Override
912 public Object getDocumentDataObject() {
913 return getNewMaintainableObject().getDataObject();
914 }
915
916
917
918
919
920
921
922
923
924
925
926 @Override
927 public GloballyUnique getNoteTarget() {
928 if (getNewMaintainableObject() == null) {
929 throw new IllegalStateException(
930 "Failed to acquire the note target. The new maintainable object on this document is null.");
931 }
932 if (getNewMaintainableObject().isNotesEnabled() && getDocumentDataObject() instanceof GloballyUnique ) {
933 return (GloballyUnique) getDocumentDataObject();
934 }
935 return super.getNoteTarget();
936 }
937
938
939
940
941
942
943
944
945
946
947
948
949
950 @Override
951 public NoteType getNoteType() {
952 if (getNewMaintainableObject().isNotesEnabled()) {
953 return NoteType.BUSINESS_OBJECT;
954 }
955 return super.getNoteType();
956 }
957
958 @Override
959 public PropertySerializabilityEvaluator getDocumentPropertySerizabilityEvaluator() {
960 String docTypeName = "";
961 if (newMaintainableObject != null) {
962 docTypeName = getDocumentDictionaryService().getMaintenanceDocumentTypeName(
963 this.newMaintainableObject.getDataObjectClass());
964 } else {
965
966
967 if (getDocumentHeader() != null && getDocumentHeader().getWorkflowDocument() != null) {
968 docTypeName = getDocumentHeader().getWorkflowDocument().getDocumentTypeName();
969 }
970 }
971 if (!StringUtils.isBlank(docTypeName)) {
972 DocumentEntry documentEntry = getDocumentDictionaryService().getMaintenanceDocumentEntry(docTypeName);
973 if (documentEntry != null) {
974 WorkflowProperties workflowProperties = documentEntry.getWorkflowProperties();
975 WorkflowAttributes workflowAttributes = documentEntry.getWorkflowAttributes();
976 return createPropertySerializabilityEvaluator(workflowProperties, workflowAttributes);
977 } else {
978 LOG.error("Unable to obtain DD DocumentEntry for document type: '" + docTypeName + "'");
979 }
980 } else {
981 LOG.error("Unable to obtain document type name for this document: " + this);
982 }
983 LOG.error("Returning null for the PropertySerializabilityEvaluator");
984 return null;
985 }
986
987 public DocumentAttachment getAttachment() {
988 return this.attachment;
989 }
990
991 public void setAttachment(DocumentAttachment attachment) {
992 this.attachment = attachment;
993 }
994
995 public List<MultiDocumentAttachment> getAttachments() {
996 return this.attachments;
997 }
998
999 public void setAttachments(List<MultiDocumentAttachment> attachments) {
1000 this.attachments = attachments;
1001 }
1002
1003 public String getAttachmentPropertyName() {
1004 return this.attachmentPropertyName;
1005 }
1006
1007 public void setAttachmentPropertyName(String attachmentPropertyName) {
1008 this.attachmentPropertyName = attachmentPropertyName;
1009 }
1010
1011 public String getAttachmentListPropertyName() {
1012 return this.attachmentListPropertyName;
1013 }
1014
1015 public void setAttachmentListPropertyName(String attachmentListPropertyName) {
1016 this.attachmentListPropertyName = attachmentListPropertyName;
1017 }
1018
1019 public String getAttachmentCollectionName() {
1020 return this.attachmentCollectionName;
1021 }
1022
1023 public void setAttachmentCollectionName(String attachmentCollectionName) {
1024 this.attachmentCollectionName = attachmentCollectionName;
1025 }
1026
1027
1028
1029
1030
1031
1032
1033
1034 public boolean isSessionDocument() {
1035 return SessionDocument.class.isAssignableFrom(this.getClass());
1036 }
1037
1038
1039
1040
1041
1042
1043
1044
1045 @Override
1046 public boolean useCustomLockDescriptors() {
1047 return (newMaintainableObject != null && newMaintainableObject.useCustomLockDescriptors());
1048 }
1049
1050
1051
1052
1053
1054
1055
1056
1057 @Override
1058 public String getCustomLockDescriptor(Person user) {
1059 if (newMaintainableObject == null) {
1060 throw new PessimisticLockingException("Maintenance Document " + getDocumentNumber() +
1061 " is using pessimistic locking with custom lock descriptors, but no new maintainable object has been defined");
1062 }
1063 return newMaintainableObject.getCustomLockDescriptor(user);
1064 }
1065
1066 protected DocumentDictionaryService getDocumentDictionaryService() {
1067 if (documentDictionaryService == null) {
1068 documentDictionaryService = KRADServiceLocatorWeb.getDocumentDictionaryService();
1069 }
1070 return documentDictionaryService;
1071 }
1072
1073 protected MaintenanceDocumentService getMaintenanceDocumentService() {
1074 if (maintenanceDocumentService == null) {
1075 maintenanceDocumentService = KRADServiceLocatorWeb.getMaintenanceDocumentService();
1076 }
1077 return maintenanceDocumentService;
1078 }
1079
1080 protected DocumentService getDocumentService() {
1081 if (documentService == null) {
1082 documentService = KRADServiceLocatorWeb.getDocumentService();
1083 }
1084 return documentService;
1085 }
1086
1087
1088
1089
1090 protected BusinessObjectSerializerService getBusinessObjectSerializerService() {
1091 return KRADServiceLocator.getDataObjectSerializerService();
1092 }
1093
1094
1095 protected boolean checkAllowsRecordDeletion() {
1096 Boolean allowsRecordDeletion = KRADServiceLocatorWeb.getDocumentDictionaryService().getAllowsRecordDeletion(
1097 this.getNewMaintainableObject().getDataObjectClass());
1098 if (allowsRecordDeletion != null) {
1099 return allowsRecordDeletion.booleanValue();
1100 } else {
1101 return false;
1102 }
1103 }
1104
1105
1106 protected boolean checkMaintenanceAction() {
1107 return this.getNewMaintainableObject().getMaintenanceAction().equals(KRADConstants.MAINTENANCE_DELETE_ACTION);
1108 }
1109
1110
1111 protected boolean checkDeletePermission(Object dataObject) {
1112 boolean allowsMaintain = false;
1113
1114 String maintDocTypeName = KRADServiceLocatorWeb.getDocumentDictionaryService().getMaintenanceDocumentTypeName(
1115 dataObject.getClass());
1116
1117 if (StringUtils.isNotBlank(maintDocTypeName)) {
1118 allowsMaintain = KRADServiceLocatorWeb.getDataObjectAuthorizationService().canMaintain(dataObject,
1119 GlobalVariables.getUserSession().getPerson(), maintDocTypeName);
1120 }
1121 return allowsMaintain;
1122 }
1123 }