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