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