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