001: /*
002: * Copyright 2005-2006 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.doctype;
018:
019: import java.util.ArrayList;
020: import java.util.Collection;
021: import java.util.Collections;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: import org.apache.commons.lang.StringUtils;
026: import org.apache.log4j.Logger;
027: import org.kuali.rice.core.Core;
028: import org.kuali.rice.definition.ObjectDefinition;
029: import org.kuali.rice.resourceloader.GlobalResourceLoader;
030:
031: import edu.iu.uis.eden.EdenConstants;
032: import edu.iu.uis.eden.KEWServiceLocator;
033: import edu.iu.uis.eden.WorkflowPersistable;
034: import edu.iu.uis.eden.clientapp.PostProcessorRemote;
035: import edu.iu.uis.eden.clientapp.vo.DocumentTypeVO;
036: import edu.iu.uis.eden.docsearch.StandardDocumentSearchGenerator;
037: import edu.iu.uis.eden.docsearch.DocumentSearchGenerator;
038: import edu.iu.uis.eden.docsearch.DocumentSearchResultProcessor;
039: import edu.iu.uis.eden.docsearch.SearchableAttribute;
040: import edu.iu.uis.eden.docsearch.StandardDocumentSearchResultProcessor;
041: import edu.iu.uis.eden.docsearch.xml.DocumentSearchXMLResultProcessor;
042: import edu.iu.uis.eden.docsearch.xml.GenericXMLSearchableAttribute;
043: import edu.iu.uis.eden.engine.node.Process;
044: import edu.iu.uis.eden.exception.ResourceUnavailableException;
045: import edu.iu.uis.eden.exception.WorkflowRuntimeException;
046: import edu.iu.uis.eden.notes.CustomNoteAttribute;
047: import edu.iu.uis.eden.plugin.attributes.CustomActionListAttribute;
048: import edu.iu.uis.eden.plugin.attributes.CustomEmailAttribute;
049: import edu.iu.uis.eden.postprocessor.DefaultPostProcessor;
050: import edu.iu.uis.eden.postprocessor.PostProcessor;
051: import edu.iu.uis.eden.postprocessor.PostProcessorRemoteAdapter;
052: import edu.iu.uis.eden.routetemplate.RuleAttribute;
053: import edu.iu.uis.eden.server.BeanConverter;
054: import edu.iu.uis.eden.user.WorkflowUser;
055: import edu.iu.uis.eden.util.CodeTranslator;
056: import edu.iu.uis.eden.util.Utilities;
057: import edu.iu.uis.eden.workgroup.WorkflowGroupId;
058: import edu.iu.uis.eden.workgroup.Workgroup;
059:
060: /**
061: * Model bean mapped to ojb representing a document type. Provides component lookup behavior that
062: * can construct {@link ObjectDefinition} objects correctly to account for MessageEntity inheritance.
063: * Can also navigate parent hierarchy when getting data/components.
064: *
065: * @author rkirkend
066: * @author ewestfal
067: */
068: public class DocumentType implements WorkflowPersistable {
069: private static final Logger LOG = Logger
070: .getLogger(DocumentType.class);
071:
072: private static final long serialVersionUID = 1312830153583125069L;
073:
074: private Long documentTypeId;
075: private Long docTypeParentId;
076: private String name;
077: private Integer version = new Integer(0);
078: private Boolean activeInd;
079: private Boolean currentInd;
080: private String description;
081: private String label;
082: private Long previousVersionId;
083: private Long routeHeaderId;
084: private String docHandlerUrl;
085: private String postProcessorName;
086: private Long workgroupId;
087: private Long blanketApproveWorkgroupId;
088: private String blanketApprovePolicy;
089: private String messageEntity;
090: private Integer lockVerNbr;
091:
092: /* these two fields are for the web tier lookupable
093: * DocumentType is doing double-duty as a web/business tier object
094: */
095: private String returnUrl;
096: private String actionsUrl;
097:
098: /* The default exception workgroup to apply to nodes that lack an exception workgroup definition.
099: * Used at parse-time only; not stored in db.
100: */
101: private Workgroup defaultExceptionWorkgroup;
102:
103: private Collection policies;
104: private List routeLevels;
105: private Collection childrenDocTypes;
106: private List<DocumentTypeAttribute> documentTypeAttributes;
107:
108: /* New Workflow 2.1 Field */
109: private List processes = new ArrayList();
110: private String routingVersion = EdenConstants.CURRENT_ROUTING_VERSION;
111:
112: /* Workflow 2.2 Fields */
113: private String notificationFromAddress;
114:
115: /* Workflow 2.4 XSLT-based email message customization */
116: private String customEmailStylesheet;
117:
118: public DocumentType() {
119: routeLevels = new ArrayList();
120: documentTypeAttributes = new ArrayList<DocumentTypeAttribute>();
121: policies = new ArrayList();
122: version = new Integer(0);
123: }
124:
125: public DocumentTypePolicy getDefaultApprovePolicy() {
126: return getPolicyByName(EdenConstants.DEFAULT_APPROVE_POLICY,
127: Boolean.TRUE);
128: }
129:
130: public DocumentTypePolicy getInitiatorMustRoutePolicy() {
131: return getPolicyByName(
132: EdenConstants.INITIATOR_MUST_ROUTE_POLICY, Boolean.TRUE);
133: }
134:
135: public DocumentTypePolicy getInitiatorMustSavePolicy() {
136: return getPolicyByName(
137: EdenConstants.INITIATOR_MUST_SAVE_POLICY, Boolean.TRUE);
138: }
139:
140: public DocumentTypePolicy getInitiatorMustCancelPolicy() {
141: return getPolicyByName(
142: EdenConstants.INITIATOR_MUST_CANCEL_POLICY,
143: Boolean.TRUE);
144: }
145:
146: public DocumentTypePolicy getInitiatorMustBlanketApprovePolicy() {
147: return getPolicyByName(
148: EdenConstants.INITIATOR_MUST_BLANKET_APPROVE_POLICY,
149: Boolean.TRUE);
150: }
151:
152: public DocumentTypePolicy getPreApprovePolicy() {
153: return getPolicyByName(EdenConstants.PREAPPROVE_POLICY,
154: Boolean.TRUE);
155: }
156:
157: public DocumentTypePolicy getLookIntoFuturePolicy() {
158: return getPolicyByName(EdenConstants.LOOK_INTO_FUTURE_POLICY,
159: Boolean.FALSE);
160: }
161:
162: public DocumentTypePolicy getSuperUserApproveNotificationPolicy() {
163: return getPolicyByName(
164: DocumentTypePolicyEnum.SEND_NOTIFICATION_ON_SU_APPROVE
165: .getName(), Boolean.FALSE);
166: }
167:
168: public DocumentTypePolicy getSupportsQuickInitiatePolicy() {
169: return getPolicyByName(
170: EdenConstants.SUPPORTS_QUICK_INITIATE_POLICY,
171: Boolean.TRUE);
172: }
173:
174: public DocumentTypePolicy getNotifyOnSavePolicy() {
175: return getPolicyByName(EdenConstants.NOTIFY_ON_SAVE_POLICY,
176: Boolean.FALSE);
177: }
178:
179: public String getDefaultApprovePolicyDisplayValue() {
180: if (getDefaultApprovePolicy() != null) {
181: return getDefaultApprovePolicy().getPolicyDisplayValue();
182: }
183: return null;
184: }
185:
186: public String getInitiatorMustRouteDisplayValue() {
187: if (getInitiatorMustRoutePolicy() != null) {
188: return getInitiatorMustRoutePolicy()
189: .getPolicyDisplayValue();
190: }
191: return null;
192: }
193:
194: public String getInitiatorMustSaveDisplayValue() {
195: if (getInitiatorMustSavePolicy() != null) {
196: return getInitiatorMustSavePolicy().getPolicyDisplayValue();
197: }
198: return null;
199: }
200:
201: public String getPreApprovePolicyDisplayValue() {
202: if (getPreApprovePolicy() != null) {
203: return getPreApprovePolicy().getPolicyDisplayValue();
204: }
205: return null;
206: }
207:
208: public void addSearchableAttribute(
209: DocumentTypeAttribute searchableAttribute) {
210: documentTypeAttributes.add(searchableAttribute);
211: }
212:
213: public boolean hasSearchableAttributes() {
214: return !getSearchableAttributes().isEmpty();
215: }
216:
217: public List<SearchableAttribute> getSearchableAttributes() {
218: List<SearchableAttribute> searchAtts = new ArrayList<SearchableAttribute>();
219: if ((documentTypeAttributes == null || documentTypeAttributes
220: .isEmpty())) {
221: if (getParentDocType() != null) {
222: return getParentDocType().getSearchableAttributes();
223: } else {
224: return searchAtts;
225: }
226: }
227:
228: for (Iterator iterator = documentTypeAttributes.iterator(); iterator
229: .hasNext();) {
230: DocumentTypeAttribute attribute = (DocumentTypeAttribute) iterator
231: .next();
232: // String attributeType = attribute.getRuleAttribute().getType();
233: RuleAttribute ruleAttribute = attribute.getRuleAttribute();
234: SearchableAttribute searchableAttribute = null;
235: if (EdenConstants.SEARCHABLE_ATTRIBUTE_TYPE
236: .equals(ruleAttribute.getType())) {
237: ObjectDefinition objDef = getAttributeObjectDefinition(ruleAttribute);
238: searchableAttribute = (SearchableAttribute) GlobalResourceLoader
239: .getObject(objDef);
240: } else if (EdenConstants.SEARCHABLE_XML_ATTRIBUTE_TYPE
241: .equals(ruleAttribute.getType())) {
242: ObjectDefinition objDef = getAttributeObjectDefinition(ruleAttribute);
243: searchableAttribute = (SearchableAttribute) GlobalResourceLoader
244: .getObject(objDef);
245: //required to make it work because ruleAttribute XML is required to construct fields
246: ((GenericXMLSearchableAttribute) searchableAttribute)
247: .setRuleAttribute(ruleAttribute);
248: }
249: if (searchableAttribute != null) {
250: searchAtts.add(searchableAttribute);
251: }
252: }
253: return searchAtts;
254: }
255:
256: public DocumentTypeAttribute getDocumentTypeAttribute(int index) {
257: while (getDocumentTypeAttributes().size() <= index) {
258: DocumentTypeAttribute attribute = new DocumentTypeAttribute();
259: //attribute.setDocumentTypeId(this.documentTypeId);
260: getDocumentTypeAttributes().add(attribute);
261: }
262: return (DocumentTypeAttribute) getDocumentTypeAttributes().get(
263: index);
264: }
265:
266: public void setDocumentTypeAttribute(int index,
267: DocumentTypeAttribute documentTypeAttribute) {
268: documentTypeAttributes.set(index, documentTypeAttribute);
269: }
270:
271: public String getDocTypeActiveIndicatorDisplayValue() {
272: if (getActiveInd() == null) {
273: return EdenConstants.INACTIVE_LABEL_LOWER;
274: }
275: return CodeTranslator.getActiveIndicatorLabel(getActiveInd());
276: }
277:
278: public Collection getChildrenDocTypes() {
279: if (this .childrenDocTypes == null) {
280: this .childrenDocTypes = KEWServiceLocator
281: .getDocumentTypeService().getChildDocumentTypes(
282: this );
283: }
284: return childrenDocTypes;
285: }
286:
287: public java.lang.Long getDocTypeParentId() {
288: return docTypeParentId;
289: }
290:
291: public void setDocTypeParentId(java.lang.Long docTypeParentId) {
292: this .docTypeParentId = docTypeParentId;
293: }
294:
295: public DocumentType getParentDocType() {
296: return KEWServiceLocator.getDocumentTypeService().findById(
297: this .docTypeParentId);
298: }
299:
300: public Collection getPolicies() {
301: return policies;
302: }
303:
304: public void setPolicies(Collection policies) {
305: this .policies = policies;
306: }
307:
308: public List getRouteLevels() {
309: if (routeLevels.isEmpty() && getParentDocType() != null) {
310: return getParentRouteLevels(getParentDocType());
311: }
312: return routeLevels;
313: }
314:
315: private List getParentRouteLevels(DocumentType parent) {
316: if (parent.getRouteLevels() == null) {
317: return getParentRouteLevels(parent.getParentDocType());
318: } else {
319: return parent.getRouteLevels();
320: }
321: }
322:
323: public void setRouteLevels(List routeLevels) {
324: this .routeLevels = routeLevels;
325: }
326:
327: public String getActionsUrl() {
328: return actionsUrl;
329: }
330:
331: public void setActionsUrl(String actions) {
332: this .actionsUrl = actions;
333: }
334:
335: public Boolean getActiveInd() {
336: return activeInd;
337: }
338:
339: public void setActiveInd(java.lang.Boolean activeInd) {
340: this .activeInd = activeInd;
341: }
342:
343: public java.lang.Boolean getCurrentInd() {
344: return currentInd;
345: }
346:
347: public void setCurrentInd(java.lang.Boolean currentInd) {
348: this .currentInd = currentInd;
349: }
350:
351: public java.lang.String getDescription() {
352: return description;
353: }
354:
355: public void setDescription(java.lang.String description) {
356: this .description = description;
357: }
358:
359: public String getDocHandlerUrl() {
360: return resolveDocHandlerUrl(docHandlerUrl);
361: }
362:
363: public String getUnresolvedDocHandlerUrl() {
364: return docHandlerUrl;
365: }
366:
367: /**
368: * If the doc handler URL has variables in it that need to be replaced, this will look up the values
369: * for those variables and replace them in the doc handler URL.
370: */
371: protected String resolveDocHandlerUrl(String docHandlerUrl) {
372: return Utilities.substituteConfigParameters(docHandlerUrl);
373: }
374:
375: public void setDocHandlerUrl(java.lang.String docHandlerUrl) {
376: this .docHandlerUrl = docHandlerUrl;
377: }
378:
379: public java.lang.String getLabel() {
380: return label;
381: }
382:
383: public void setLabel(java.lang.String label) {
384: this .label = label;
385: }
386:
387: public java.lang.String getName() {
388: return name;
389: }
390:
391: public void setName(java.lang.String name) {
392: this .name = name;
393: }
394:
395: public java.lang.String getPostProcessorName() {
396: return postProcessorName;
397: }
398:
399: public void setPostProcessorName(java.lang.String postProcessorName) {
400: this .postProcessorName = postProcessorName;
401: }
402:
403: public java.lang.Long getPreviousVersionId() {
404: return previousVersionId;
405: }
406:
407: public void setPreviousVersionId(java.lang.Long previousVersionId) {
408: this .previousVersionId = previousVersionId;
409: }
410:
411: public java.lang.Long getRouteHeaderId() {
412: return routeHeaderId;
413: }
414:
415: public void setRouteHeaderId(java.lang.Long routeHeaderId) {
416: this .routeHeaderId = routeHeaderId;
417: }
418:
419: public java.lang.Integer getVersion() {
420: return version;
421: }
422:
423: public void setVersion(java.lang.Integer version) {
424: this .version = version;
425: }
426:
427: public java.lang.Long getDocumentTypeId() {
428: return documentTypeId;
429: }
430:
431: public void setDocumentTypeId(java.lang.Long docTypeGrpId) {
432: this .documentTypeId = docTypeGrpId;
433: }
434:
435: public Object copy(boolean preserveKeys) {
436: throw new UnsupportedOperationException(
437: "The copy method is deprecated and unimplemented!");
438: }
439:
440: public java.lang.String getReturnUrl() {
441: return returnUrl;
442: }
443:
444: public void setReturnUrl(java.lang.String returnUrl) {
445: this .returnUrl = returnUrl;
446: }
447:
448: private DocumentTypePolicy getPolicyByName(String policyName,
449: Boolean defaultValue) {
450:
451: Iterator policyIter = getPolicies().iterator();
452: while (policyIter.hasNext()) {
453: DocumentTypePolicy policy = (DocumentTypePolicy) policyIter
454: .next();
455: if (policyName.equals(policy.getPolicyName())) {
456: policy.setInheritedFlag(Boolean.FALSE);
457: return policy;
458: }
459: }
460:
461: if (getParentDocType() != null) {
462: DocumentTypePolicy policy = getParentDocType()
463: .getPolicyByName(policyName, defaultValue);
464: policy.setInheritedFlag(Boolean.TRUE);
465: if (policy.getPolicyValue() == null) {
466: policy.setPolicyValue(Boolean.TRUE);
467: }
468: return policy;
469: }
470: DocumentTypePolicy policy = new DocumentTypePolicy();
471: policy.setPolicyName(policyName);
472: policy.setInheritedFlag(Boolean.FALSE);
473: policy.setPolicyValue(defaultValue);
474: return policy;
475: }
476:
477: public Integer getLockVerNbr() {
478: return lockVerNbr;
479: }
480:
481: public void setLockVerNbr(Integer lockVerNbr) {
482: this .lockVerNbr = lockVerNbr;
483: }
484:
485: /**
486: * @deprecated
487: */
488: public DocumentTypeVO getDocumentTypeVO() {
489: return BeanConverter.convertDocumentType(this );
490: }
491:
492: private DocumentTypeService getDocumentTypeService() {
493: return (DocumentTypeService) KEWServiceLocator
494: .getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE);
495: }
496:
497: public Workgroup getSuperUserWorkgroup() {
498: return KEWServiceLocator.getWorkgroupService().getWorkgroup(
499: new WorkflowGroupId(this .workgroupId));
500: }
501:
502: public void setSuperUserWorkgroup(Workgroup suWorkgroup) {
503: this .workgroupId = suWorkgroup.getWorkflowGroupId()
504: .getGroupId();
505: }
506:
507: public DocumentType getPreviousVersion() {
508: return getDocumentTypeService().findById(previousVersionId);
509: }
510:
511: public Workgroup getBlanketApproveWorkgroup() {
512: return KEWServiceLocator.getWorkgroupService().getWorkgroup(
513: new WorkflowGroupId(this .blanketApproveWorkgroupId));
514: }
515:
516: public void setBlanketApproveWorkgroup(
517: Workgroup blanketApproveWorkgroup) {
518: this .blanketApproveWorkgroupId = blanketApproveWorkgroup
519: .getWorkflowGroupId().getGroupId();
520: }
521:
522: public String getBlanketApprovePolicy() {
523: return this .blanketApprovePolicy;
524: }
525:
526: public void setBlanketApprovePolicy(String blanketApprovePolicy) {
527: this .blanketApprovePolicy = blanketApprovePolicy;
528: }
529:
530: public Workgroup getBlanketApproveWorkgroupWithInheritance() {
531: if (getParentDocType() != null
532: && this .blanketApproveWorkgroupId == null) {
533: return getParentDocType()
534: .getBlanketApproveWorkgroupWithInheritance();
535: }
536: return KEWServiceLocator.getWorkgroupService().getWorkgroup(
537: new WorkflowGroupId(this .blanketApproveWorkgroupId));
538: }
539:
540: public boolean isUserBlanketApprover(WorkflowUser user) {
541: if (EdenConstants.DOCUMENT_TYPE_BLANKET_APPROVE_POLICY_NONE
542: .equalsIgnoreCase(getBlanketApprovePolicy())) {
543: // no one can blanket approve this doc type
544: return false;
545: } else if (EdenConstants.DOCUMENT_TYPE_BLANKET_APPROVE_POLICY_ANY
546: .equalsIgnoreCase(getBlanketApprovePolicy())) {
547: // anyone can blanket approve this doc type
548: return true;
549: }
550: Workgroup blanketApproveGroup = getBlanketApproveWorkgroup();
551: if (blanketApproveGroup != null) {
552: // found blanket approve group on this doc type
553: return blanketApproveGroup.hasMember(user);
554: } else if (this .blanketApproveWorkgroupId != null) {
555: // found no valid workgroup but we have a workgroup id somehow
556: throw new WorkflowRuntimeException(
557: "Could not locate valid workgroup for given blanket approve workgroup id '"
558: + this .blanketApproveWorkgroupId + "'");
559: }
560: DocumentType parentDoc = getParentDocType();
561: if (parentDoc != null) {
562: // found parent doc so try to get blanket approver info from it
563: return parentDoc.isUserBlanketApprover(user);
564: }
565: return false;
566: }
567:
568: public Workgroup getDefaultExceptionWorkgroup() {
569: return defaultExceptionWorkgroup;
570: }
571:
572: public void setDefaultExceptionWorkgroup(
573: Workgroup defaultExceptionWorkgroup) {
574: this .defaultExceptionWorkgroup = defaultExceptionWorkgroup;
575: }
576:
577: public DocumentSearchGenerator getDocumentSearchGenerator() {
578: ObjectDefinition objDef = getAttributeObjectDefinition(EdenConstants.SEARCH_GENERATOR_ATTRIBUTE_TYPE);
579: if (objDef == null) {
580: return new StandardDocumentSearchGenerator(
581: getSearchableAttributes());
582: }
583: Object searchGenerator = GlobalResourceLoader.getObject(objDef);
584: if (searchGenerator == null) {
585: throw new WorkflowRuntimeException(
586: "Could not locate DocumentSearchGenerator in this JVM or at message entity "
587: + getMessageEntity() + ": "
588: + objDef.getClassName());
589: }
590: DocumentSearchGenerator docSearchGenerator = (DocumentSearchGenerator) searchGenerator;
591: docSearchGenerator
592: .setSearchableAttributes(getSearchableAttributes());
593: return docSearchGenerator;
594: }
595:
596: public DocumentSearchResultProcessor getDocumentSearchResultProcessor() {
597: if ((documentTypeAttributes == null || documentTypeAttributes
598: .isEmpty())) {
599: if (getParentDocType() != null) {
600: return getParentDocType()
601: .getDocumentSearchResultProcessor();
602: } else {
603: return new StandardDocumentSearchResultProcessor();
604: }
605: }
606: for (Iterator iterator = documentTypeAttributes.iterator(); iterator
607: .hasNext();) {
608: DocumentTypeAttribute attribute = (DocumentTypeAttribute) iterator
609: .next();
610: RuleAttribute ruleAttribute = attribute.getRuleAttribute();
611: if (EdenConstants.SEARCH_RESULT_PROCESSOR_ATTRIBUTE_TYPE
612: .equals(ruleAttribute.getType())) {
613: ObjectDefinition objDef = getAttributeObjectDefinition(ruleAttribute);
614: return (DocumentSearchResultProcessor) GlobalResourceLoader
615: .getObject(objDef);
616: } else if (EdenConstants.SEARCH_RESULT_XML_PROCESSOR_ATTRIBUTE_TYPE
617: .equals(ruleAttribute.getType())) {
618: ObjectDefinition objDef = getAttributeObjectDefinition(ruleAttribute);
619: DocumentSearchResultProcessor resultProcessor = (DocumentSearchResultProcessor) GlobalResourceLoader
620: .getObject(objDef);
621: //required to make it work because ruleAttribute XML is required to construct custom columns
622: ((DocumentSearchXMLResultProcessor) resultProcessor)
623: .setRuleAttribute(ruleAttribute);
624: return resultProcessor;
625: }
626: }
627: return new StandardDocumentSearchResultProcessor();
628: }
629:
630: public CustomActionListAttribute getCustomActionListAttribute()
631: throws ResourceUnavailableException {
632:
633: ObjectDefinition objDef = getAttributeObjectDefinition(EdenConstants.ACTION_LIST_ATTRIBUTE_TYPE);
634: if (objDef == null) {
635: return null;
636: }
637: try {
638: return (CustomActionListAttribute) GlobalResourceLoader
639: .getObject(objDef);
640: } catch (RuntimeException e) {
641: LOG.error("Error obtaining custom action list attribute: "
642: + objDef, e);
643: throw e;
644: }
645:
646: }
647:
648: public CustomEmailAttribute getCustomEmailAttribute()
649: throws ResourceUnavailableException {
650: ObjectDefinition objDef = getAttributeObjectDefinition(EdenConstants.EMAIL_ATTRIBUTE_TYPE);
651: if (objDef == null) {
652: return null;
653: }
654: return (CustomEmailAttribute) GlobalResourceLoader
655: .getObject(objDef);
656: }
657:
658: public ObjectDefinition getAttributeObjectDefinition(String typeCode) {
659: for (Iterator iter = getDocumentTypeAttributes().iterator(); iter
660: .hasNext();) {
661: RuleAttribute attribute = ((DocumentTypeAttribute) iter
662: .next()).getRuleAttribute();
663: if (attribute.getType().equals(typeCode)) {
664: return getAttributeObjectDefinition(attribute);
665: }
666: }
667: if (getParentDocType() != null) {
668: return getParentDocType().getAttributeObjectDefinition(
669: typeCode);
670: }
671: return null;
672: }
673:
674: public ObjectDefinition getAttributeObjectDefinition(
675: RuleAttribute ruleAttribute) {
676: if (ruleAttribute.getMessageEntity() == null) {
677: return new ObjectDefinition(ruleAttribute.getClassName(),
678: this .getMessageEntity());
679: } else {
680: return new ObjectDefinition(ruleAttribute.getClassName(),
681: ruleAttribute.getMessageEntity());
682: }
683: }
684:
685: public CustomNoteAttribute getCustomNoteAttribute()
686: throws ResourceUnavailableException {
687: ObjectDefinition objDef = getAttributeObjectDefinition(EdenConstants.NOTE_ATTRIBUTE_TYPE);
688: if (objDef == null) {
689: String defaultNoteClass = Core.getCurrentContextConfig()
690: .getDefaultNoteClass();
691: if (defaultNoteClass == null) {
692: return null;
693: }
694: objDef = new ObjectDefinition(defaultNoteClass);
695: }
696: return (CustomNoteAttribute) GlobalResourceLoader
697: .getObject(objDef);
698: }
699:
700: public PostProcessor getPostProcessor() {
701: String pname = getPostProcessorName();
702: if (StringUtils.isBlank(pname)) {
703: return new DefaultPostProcessor();
704: }
705:
706: ObjectDefinition objDef = getObjectDefinition(pname);
707: Object postProcessor = GlobalResourceLoader.getObject(objDef);
708: if (postProcessor == null) {
709: throw new WorkflowRuntimeException(
710: "Could not locate PostProcessor in this JVM or at message entity "
711: + getMessageEntity() + ": " + pname);
712: }
713: if (postProcessor instanceof PostProcessorRemote) {
714: postProcessor = new PostProcessorRemoteAdapter(
715: (PostProcessorRemote) postProcessor);
716: }
717:
718: return (PostProcessor) postProcessor;
719: }
720:
721: public ObjectDefinition getObjectDefinition(String objectName) {
722: return new ObjectDefinition(objectName, getMessageEntity());
723: }
724:
725: /**
726: * Returns true if this document type defines it's own routing, false if it inherits its routing
727: * from a parent document type.
728: */
729: public boolean isRouteInherited() {
730: return processes.isEmpty() && getParentDocType() != null;
731: }
732:
733: /**
734: * Returns the DocumentType which defines the route for this document. This is the DocumentType
735: * from which we inherit our Processes which define our routing.
736: */
737: public DocumentType getRouteDefiningDocumentType() {
738: if (isRouteInherited()) {
739: return getParentDocType().getRouteDefiningDocumentType();
740: }
741: return this ;
742: }
743:
744: public boolean isSearchableAttributesInherited() {
745: return documentTypeAttributes.isEmpty()
746: && getParentDocType() != null;
747: }
748:
749: public boolean isDocTypeActive() {
750: if (!activeInd.booleanValue()) {
751: return false;
752: }
753: if (getParentDocType() != null) {
754: if (!getParentActiveInd(getParentDocType())) {
755: return false;
756: }
757: }
758: return true;
759: }
760:
761: private boolean getParentActiveInd(DocumentType parentDocType) {
762: if (parentDocType.getActiveInd() == null
763: || parentDocType.getActiveInd().booleanValue()) {
764: if (parentDocType.getParentDocType() != null) {
765: return getParentActiveInd(parentDocType
766: .getParentDocType());
767: }
768: return true;
769: } else {
770: return false;
771: }
772: }
773:
774: /**
775: * @param documentTypeAttributes The documentTypeAttributes to set.
776: */
777: public void setDocumentTypeAttributes(
778: List<DocumentTypeAttribute> documentTypeAttributes) {
779: this .documentTypeAttributes = documentTypeAttributes;
780: }
781:
782: /**
783: * @return Returns the documentTypeAttributes.
784: */
785: public List<DocumentTypeAttribute> getDocumentTypeAttributes() {
786: return documentTypeAttributes;
787: }
788:
789: // public List<DocumentTypeAttribute> getDocumentTypeAttributesWithPotentialInheritance() {
790: // if ((documentTypeAttributes == null || documentTypeAttributes.isEmpty())) {
791: // if (getParentDocType() != null) {
792: // return getParentDocType().getDocumentTypeAttributesWithPotentialInheritance();
793: // } else {
794: // return documentTypeAttributes;
795: // }
796: // }
797: // return new ArrayList<DocumentTypeAttribute>();
798: // }
799:
800: public void addProcess(Process process) {
801: processes.add(process);
802: }
803:
804: /**
805: * Gets the processes of this document by checking locally for processes, and if none are
806: * present, retrieves them from it's parent document type. The list returned is an immutable
807: * list. To add processes to a document type, use the addProcess method.
808: *
809: * NOTE: Since OJB uses direct field access, this will not interfere with the proper
810: * mapping of the processes field.
811: * @return
812: */
813: public List getProcesses() {
814: if (processes.isEmpty() && getParentDocType() != null) {
815: return getParentProcesses(getParentDocType());
816: }
817: return Collections.unmodifiableList(processes);
818: }
819:
820: public void setProcesses(List routeNodes) {
821: this .processes = routeNodes;
822: }
823:
824: private List getParentProcesses(DocumentType parent) {
825: List parentProcesses = parent.getProcesses();
826: if (parentProcesses == null) {
827: parentProcesses = getParentProcesses(parent
828: .getParentDocType());
829: }
830: return parentProcesses;
831: }
832:
833: public Process getPrimaryProcess() {
834: for (Iterator iterator = getProcesses().iterator(); iterator
835: .hasNext();) {
836: Process process = (Process) iterator.next();
837: if (process.isInitial()) {
838: return process;
839: }
840: }
841: return null;
842: }
843:
844: public Process getNamedProcess(String name) {
845: for (Iterator iterator = getProcesses().iterator(); iterator
846: .hasNext();) {
847: Process process = (Process) iterator.next();
848: if (Utilities.equals(name, process.getName())) {
849: return process;
850: }
851: }
852: return null;
853: }
854:
855: public String getRoutingVersion() {
856: return routingVersion;
857: }
858:
859: public void setRoutingVersion(String routingVersion) {
860: this .routingVersion = routingVersion;
861: }
862:
863: public String getNotificationFromAddress() {
864: if (notificationFromAddress == null
865: && getParentDocType() != null) {
866: return getParentDocType().getNotificationFromAddress();
867: }
868: return notificationFromAddress;
869: }
870:
871: public void setNotificationFromAddress(
872: String notificationFromAddress) {
873: this .notificationFromAddress = notificationFromAddress;
874: }
875:
876: public boolean isParentOf(DocumentType documentType) {
877: // this is a depth-first search which works for our needs
878: for (Iterator iterator = getChildrenDocTypes().iterator(); iterator
879: .hasNext();) {
880: DocumentType child = (DocumentType) iterator.next();
881: if (child.getName().equals(documentType.getName())
882: || child.isParentOf(documentType)) {
883: return true;
884: }
885: }
886: return false;
887: }
888:
889: /**
890: * this exists because the lookup wants to make a call on a bean method when displaying results and those calls are
891: * entered programatically into the framework by method name
892: *
893: * @return
894: */
895: public String getLookupParentName() {
896: DocumentType parent = getParentDocType();
897: if (parent == null) {
898: return "Root";
899: }
900: return parent.getName();
901: }
902:
903: public boolean isSuperUser(WorkflowUser user) {
904: return getSuperUserWorkgroup().hasMember(user);
905: }
906:
907: public boolean hasPreviousVersion() {
908: if (this .documentTypeId == null) {
909: return false;
910: }
911: return !this .documentTypeId.equals(this .previousVersionId);
912: }
913:
914: public String toString() {
915: return "[DocumentType: documentTypeId=" + documentTypeId
916: + ", docTypeParentId=" + docTypeParentId + ", name="
917: + name + ", version=" + version + ", activeInd="
918: + activeInd + ", currentInd=" + currentInd
919: + ", description=" + description + ", routeHeaderId="
920: + routeHeaderId + ", docHandlerUrl=" + docHandlerUrl
921: + ", postProcessorName=" + postProcessorName
922: + ", workgroupId=" + workgroupId
923: + ", blanketApproveWorkgroupId="
924: + blanketApproveWorkgroupId + ", blanketApprovePolicy="
925: + blanketApprovePolicy + ", lockVerNbr=" + lockVerNbr
926: + ", defaultExceptionWorkgroup="
927: + defaultExceptionWorkgroup + ", policies=" + policies
928: + ", routeLevels=" + routeLevels
929: + ", childrenDocTypes=" + childrenDocTypes
930: + ", documentTypeAttributes=" + documentTypeAttributes
931: + ", processes=" + processes + ", routingVersion="
932: + routingVersion + ", notificationFromAddress="
933: + notificationFromAddress + "]";
934: }
935:
936: /**
937: * Returns the message entity for this DocumentType which can be specified on the document type itself,
938: * inherited from the parent, or defaults to the configured message entity of the application.
939: */
940: public String getMessageEntity() {
941: if (this .messageEntity != null) {
942: return messageEntity;
943: }
944: String returnVal = null;
945: if (getParentDocType() != null) {
946: returnVal = getParentDocType().getMessageEntity();
947: }
948: if (returnVal == null) {
949: // returnVal = "KEW";
950: returnVal = Core.getCurrentContextConfig()
951: .getMessageEntity();
952: }
953: return returnVal;
954: }
955:
956: /**
957: * Returns the actual specified message entity for this document type which could be null.
958: */
959: public String getActualMessageEntity() {
960: return messageEntity;
961: }
962:
963: public void setMessageEntity(String messageEntity) {
964: this .messageEntity = messageEntity;
965: }
966:
967: /**
968: * Gets the name of the custom email stylesheet to use to render email (if any has been set, null otherwise)
969: * @return name of the custom email stylesheet to use to render email (if any has been set, null otherwise)
970: */
971: public String getCustomEmailStylesheet() {
972: return customEmailStylesheet;
973: }
974:
975: /**
976: * Sets the name of the custom email stylesheet to use to render email
977: * @return name of the custom email stylesheet to use to render email
978: */
979: public void setCustomEmailStylesheet(String customEmailStylesheet) {
980: this.customEmailStylesheet = customEmailStylesheet;
981: }
982: }
|