Source Code Cross Referenced for MaintenanceDocumentRuleBase.java in  » ERP-CRM-Financial » Kuali-Financial-System » org » kuali » core » maintenance » rules » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » ERP CRM Financial » Kuali Financial System » org.kuali.core.maintenance.rules 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2005-2007 The Kuali Foundation.
0003:         * 
0004:         * Licensed under the Educational Community License, Version 1.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         * 
0008:         * http://www.opensource.org/licenses/ecl1.php
0009:         * 
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:        package org.kuali.core.maintenance.rules;
0017:
0018:        import java.util.ArrayList;
0019:        import java.util.Collection;
0020:        import java.util.Iterator;
0021:        import java.util.List;
0022:        import java.util.Map;
0023:
0024:        import org.apache.commons.lang.StringUtils;
0025:        import org.kuali.RiceConstants;
0026:        import org.kuali.RiceKeyConstants;
0027:        import org.kuali.core.authorization.FieldAuthorization;
0028:        import org.kuali.core.bo.GlobalBusinessObject;
0029:        import org.kuali.core.bo.PersistableBusinessObject;
0030:        import org.kuali.core.bo.user.UniversalUser;
0031:        import org.kuali.core.document.Document;
0032:        import org.kuali.core.document.MaintenanceDocument;
0033:        import org.kuali.core.document.authorization.MaintenanceDocumentAuthorizations;
0034:        import org.kuali.core.document.authorization.MaintenanceDocumentAuthorizer;
0035:        import org.kuali.core.exceptions.UnknownDocumentIdException;
0036:        import org.kuali.core.exceptions.ValidationException;
0037:        import org.kuali.core.maintenance.Maintainable;
0038:        import org.kuali.core.rule.AddCollectionLineRule;
0039:        import org.kuali.core.rule.event.ApproveDocumentEvent;
0040:        import org.kuali.core.rules.DocumentRuleBase;
0041:        import org.kuali.core.service.BusinessObjectDictionaryService;
0042:        import org.kuali.core.service.BusinessObjectService;
0043:        import org.kuali.core.service.DataDictionaryService;
0044:        import org.kuali.core.service.DateTimeService;
0045:        import org.kuali.core.service.DictionaryValidationService;
0046:        import org.kuali.core.service.DocumentAuthorizationService;
0047:        import org.kuali.core.service.DocumentService;
0048:        import org.kuali.core.service.KualiConfigurationService;
0049:        import org.kuali.core.service.MaintenanceDocumentDictionaryService;
0050:        import org.kuali.core.service.PersistenceService;
0051:        import org.kuali.core.service.PersistenceStructureService;
0052:        import org.kuali.core.service.UniversalUserService;
0053:        import org.kuali.core.util.ErrorMap;
0054:        import org.kuali.core.util.ErrorMessage;
0055:        import org.kuali.core.util.ForeignKeyFieldsPopulationState;
0056:        import org.kuali.core.util.GlobalVariables;
0057:        import org.kuali.core.util.ObjectUtils;
0058:        import org.kuali.core.util.TypedArrayList;
0059:        import org.kuali.core.workflow.service.KualiWorkflowDocument;
0060:        import org.kuali.core.workflow.service.WorkflowDocumentService;
0061:        import org.kuali.rice.KNSServiceLocator;
0062:
0063:        import edu.iu.uis.eden.exception.WorkflowException;
0064:
0065:        /**
0066:         * This class contains all of the business rules that are common to all maintenance documents.
0067:         * 
0068:         * 
0069:         */
0070:        public class MaintenanceDocumentRuleBase extends DocumentRuleBase
0071:                implements  MaintenanceDocumentRule, AddCollectionLineRule {
0072:            protected static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
0073:                    .getLogger(MaintenanceDocumentRuleBase.class);
0074:
0075:            // public static final String CHART_MAINTENANCE_EDOC = "ChartMaintenanceEDoc";
0076:
0077:            // these two constants are used to correctly prefix errors added to
0078:            // the global errors
0079:            public static final String MAINTAINABLE_ERROR_PREFIX = RiceConstants.MAINTENANCE_NEW_MAINTAINABLE;
0080:            public static final String DOCUMENT_ERROR_PREFIX = "document.";
0081:            public static final String MAINTAINABLE_ERROR_PATH = DOCUMENT_ERROR_PREFIX
0082:                    + "newMaintainableObject";
0083:
0084:            protected PersistenceStructureService persistenceStructureService;
0085:            protected PersistenceService persistenceService;
0086:            protected DataDictionaryService ddService;
0087:            protected BusinessObjectService boService;
0088:            protected BusinessObjectDictionaryService boDictionaryService;
0089:            protected DictionaryValidationService dictionaryValidationService;
0090:            protected KualiConfigurationService configService;
0091:            protected DocumentAuthorizationService documentAuthorizationService;
0092:            protected MaintenanceDocumentDictionaryService maintDocDictionaryService;
0093:            protected WorkflowDocumentService workflowDocumentService;
0094:            protected UniversalUserService universalUserService;
0095:
0096:            private PersistableBusinessObject oldBo;
0097:            private PersistableBusinessObject newBo;
0098:            private Class boClass;
0099:
0100:            private List priorErrorPath;
0101:
0102:            /**
0103:             * 
0104:             * Default constructor a MaintenanceDocumentRuleBase.java.
0105:             * 
0106:             */
0107:            public MaintenanceDocumentRuleBase() {
0108:
0109:                priorErrorPath = new ArrayList();
0110:
0111:                // Pseudo-inject some services.
0112:                //
0113:                // This approach is being used to make it simpler to convert the Rule classes
0114:                // to spring-managed with these services injected by Spring at some later date.
0115:                // When this happens, just remove these calls to the setters with
0116:                // SpringServiceLocator, and configure the bean defs for spring.
0117:                try {
0118:                    this .setPersistenceStructureService(KNSServiceLocator
0119:                            .getPersistenceStructureService());
0120:                    this .setDdService(KNSServiceLocator
0121:                            .getDataDictionaryService());
0122:                    this .setPersistenceService(KNSServiceLocator
0123:                            .getPersistenceService());
0124:                    this .setBoService(KNSServiceLocator
0125:                            .getBusinessObjectService());
0126:                    this .setBoDictionaryService(KNSServiceLocator
0127:                            .getBusinessObjectDictionaryService());
0128:                    this .setDictionaryValidationService(KNSServiceLocator
0129:                            .getDictionaryValidationService());
0130:                    this .setConfigService(KNSServiceLocator
0131:                            .getKualiConfigurationService());
0132:                    this .setDocumentAuthorizationService(KNSServiceLocator
0133:                            .getDocumentAuthorizationService());
0134:                    this .setMaintDocDictionaryService(KNSServiceLocator
0135:                            .getMaintenanceDocumentDictionaryService());
0136:                    this .setWorkflowDocumentService(KNSServiceLocator
0137:                            .getWorkflowDocumentService());
0138:                    this .setUniversalUserService(KNSServiceLocator
0139:                            .getUniversalUserService());
0140:                } catch (Exception ex) {
0141:                    // do nothing, avoid blowing up if called prior to spring initialization
0142:                }
0143:            }
0144:
0145:            /**
0146:             * @see org.kuali.core.maintenance.rules.MaintenanceDocumentRule#processSaveDocument(org.kuali.core.document.Document)
0147:             */
0148:            @Override
0149:            public boolean processSaveDocument(Document document) {
0150:
0151:                MaintenanceDocument maintenanceDocument = (MaintenanceDocument) document;
0152:
0153:                // remove all items from the errorPath temporarily (because it may not
0154:                // be what we expect, or what we need)
0155:                clearErrorPath();
0156:
0157:                // setup convenience pointers to the old & new bo
0158:                setupBaseConvenienceObjects(maintenanceDocument);
0159:
0160:                // the document must be in a valid state for saving. this does not include business
0161:                // rules, but just enough testing that the document is populated and in a valid state
0162:                // to not cause exceptions when saved. if this passes, then the save will always occur,
0163:                // regardless of business rules.
0164:                if (!isDocumentValidForSave(maintenanceDocument)) {
0165:                    resumeErrorPath();
0166:                    return false;
0167:                }
0168:
0169:                // apply rules that are specific to the class of the maintenance document
0170:                // (if implemented). this will always succeed if not overloaded by the
0171:                // subclass
0172:                processCustomSaveDocumentBusinessRules(maintenanceDocument);
0173:
0174:                // return the original set of items to the errorPath
0175:                resumeErrorPath();
0176:
0177:                // return the original set of items to the errorPath, to ensure no impact
0178:                // on other upstream or downstream items that rely on the errorPath
0179:                return true;
0180:            }
0181:
0182:            /**
0183:             * @see org.kuali.core.maintenance.rules.MaintenanceDocumentRule#processRouteDocument(org.kuali.core.document.Document)
0184:             */
0185:            @Override
0186:            public boolean processRouteDocument(Document document) {
0187:                LOG.info("processRouteDocument called");
0188:
0189:                MaintenanceDocument maintenanceDocument = (MaintenanceDocument) document;
0190:
0191:                // remove all items from the errorPath temporarily (because it may not
0192:                // be what we expect, or what we need)
0193:                clearErrorPath();
0194:
0195:                // setup convenience pointers to the old & new bo
0196:                setupBaseConvenienceObjects(maintenanceDocument);
0197:
0198:                // apply rules that are common across all maintenance documents, regardless of class
0199:                processGlobalSaveDocumentBusinessRules(maintenanceDocument);
0200:
0201:                // from here on, it is in a default-success mode, and will route unless one of the
0202:                // business rules stop it.
0203:                boolean success = true;
0204:
0205:                // apply rules that are common across all maintenance documents, regardless of class
0206:                success &= processGlobalRouteDocumentBusinessRules(maintenanceDocument);
0207:
0208:                // apply rules that are specific to the class of the maintenance document
0209:                // (if implemented). this will always succeed if not overloaded by the
0210:                // subclass
0211:                success &= processCustomRouteDocumentBusinessRules(maintenanceDocument);
0212:
0213:                // return the original set of items to the errorPath, to ensure no impact
0214:                // on other upstream or downstream items that rely on the errorPath
0215:                resumeErrorPath();
0216:
0217:                return success;
0218:            }
0219:
0220:            /**
0221:             * @see org.kuali.core.maintenance.rules.MaintenanceDocumentRule#processApproveDocument(ApproveDocumentEvent)
0222:             */
0223:            @Override
0224:            public boolean processApproveDocument(
0225:                    ApproveDocumentEvent approveEvent) {
0226:
0227:                MaintenanceDocument maintenanceDocument = (MaintenanceDocument) approveEvent
0228:                        .getDocument();
0229:
0230:                // remove all items from the errorPath temporarily (because it may not
0231:                // be what we expect, or what we need)
0232:                clearErrorPath();
0233:
0234:                // setup convenience pointers to the old & new bo
0235:                setupBaseConvenienceObjects(maintenanceDocument);
0236:
0237:                // apply rules that are common across all maintenance documents, regardless of class
0238:                processGlobalSaveDocumentBusinessRules(maintenanceDocument);
0239:
0240:                // from here on, it is in a default-success mode, and will approve unless one of the
0241:                // business rules stop it.
0242:                boolean success = true;
0243:
0244:                // apply rules that are common across all maintenance documents, regardless of class
0245:                success &= processGlobalApproveDocumentBusinessRules(maintenanceDocument);
0246:
0247:                // apply rules that are specific to the class of the maintenance document
0248:                // (if implemented). this will always succeed if not overloaded by the
0249:                // subclass
0250:                success &= processCustomApproveDocumentBusinessRules(maintenanceDocument);
0251:
0252:                // return the original set of items to the errorPath, to ensure no impact
0253:                // on other upstream or downstream items that rely on the errorPath
0254:                resumeErrorPath();
0255:
0256:                return success;
0257:            }
0258:
0259:            /**
0260:             * 
0261:             * This method is a convenience method to easily add a Document level error (ie, one not tied to a specific field, but
0262:             * applicable to the whole document).
0263:             * 
0264:             * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
0265:             * 
0266:             */
0267:            protected void putGlobalError(String errorConstant) {
0268:                if (!errorAlreadyExists(RiceConstants.DOCUMENT_ERRORS,
0269:                        errorConstant)) {
0270:                    GlobalVariables.getErrorMap().putErrorWithoutFullErrorPath(
0271:                            RiceConstants.DOCUMENT_ERRORS, errorConstant);
0272:                }
0273:            }
0274:
0275:            /**
0276:             * 
0277:             * This method is a convenience method to easily add a Document level error (ie, one not tied to a specific field, but
0278:             * applicable to the whole document).
0279:             * 
0280:             * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
0281:             * @param parameter - Replacement value for part of the error message.
0282:             * 
0283:             */
0284:            protected void putGlobalError(String errorConstant, String parameter) {
0285:                if (!errorAlreadyExists(RiceConstants.DOCUMENT_ERRORS,
0286:                        errorConstant)) {
0287:                    GlobalVariables.getErrorMap().putErrorWithoutFullErrorPath(
0288:                            RiceConstants.DOCUMENT_ERRORS, errorConstant,
0289:                            parameter);
0290:                }
0291:            }
0292:
0293:            /**
0294:             * 
0295:             * This method is a convenience method to easily add a Document level error (ie, one not tied to a specific field, but
0296:             * applicable to the whole document).
0297:             * 
0298:             * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
0299:             * @param parameters - Array of replacement values for part of the error message.
0300:             * 
0301:             */
0302:            protected void putGlobalError(String errorConstant,
0303:                    String[] parameters) {
0304:                if (!errorAlreadyExists(RiceConstants.DOCUMENT_ERRORS,
0305:                        errorConstant)) {
0306:                    GlobalVariables.getErrorMap().putErrorWithoutFullErrorPath(
0307:                            RiceConstants.DOCUMENT_ERRORS, errorConstant,
0308:                            parameters);
0309:                }
0310:            }
0311:
0312:            /**
0313:             * 
0314:             * This method is a convenience method to add a property-specific error to the global errors list. This method makes sure that
0315:             * the correct prefix is added to the property name so that it will display correctly on maintenance documents.
0316:             * 
0317:             * @param propertyName - Property name of the element that is associated with the error. Used to mark the field as errored in
0318:             *        the UI.
0319:             * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
0320:             * 
0321:             */
0322:            protected void putFieldError(String propertyName,
0323:                    String errorConstant) {
0324:                if (!errorAlreadyExists(MAINTAINABLE_ERROR_PREFIX
0325:                        + propertyName, errorConstant)) {
0326:                    GlobalVariables.getErrorMap().putErrorWithoutFullErrorPath(
0327:                            MAINTAINABLE_ERROR_PREFIX + propertyName,
0328:                            errorConstant);
0329:                }
0330:            }
0331:
0332:            /**
0333:             * 
0334:             * This method is a convenience method to add a property-specific error to the global errors list. This method makes sure that
0335:             * the correct prefix is added to the property name so that it will display correctly on maintenance documents.
0336:             * 
0337:             * @param propertyName - Property name of the element that is associated with the error. Used to mark the field as errored in
0338:             *        the UI.
0339:             * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
0340:             * @param parameter - Single parameter value that can be used in the message so that you can display specific values to the
0341:             *        user.
0342:             * 
0343:             */
0344:            protected void putFieldError(String propertyName,
0345:                    String errorConstant, String parameter) {
0346:                if (!errorAlreadyExists(MAINTAINABLE_ERROR_PREFIX
0347:                        + propertyName, errorConstant)) {
0348:                    GlobalVariables.getErrorMap().putErrorWithoutFullErrorPath(
0349:                            MAINTAINABLE_ERROR_PREFIX + propertyName,
0350:                            errorConstant, parameter);
0351:                }
0352:            }
0353:
0354:            /**
0355:             * 
0356:             * This method is a convenience method to add a property-specific error to the global errors list. This method makes sure that
0357:             * the correct prefix is added to the property name so that it will display correctly on maintenance documents.
0358:             * 
0359:             * @param propertyName - Property name of the element that is associated with the error. Used to mark the field as errored in
0360:             *        the UI.
0361:             * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
0362:             * @param parameters - Array of strings holding values that can be used in the message so that you can display specific values
0363:             *        to the user.
0364:             * 
0365:             */
0366:            protected void putFieldError(String propertyName,
0367:                    String errorConstant, String[] parameters) {
0368:                if (!errorAlreadyExists(MAINTAINABLE_ERROR_PREFIX
0369:                        + propertyName, errorConstant)) {
0370:                    GlobalVariables.getErrorMap().putErrorWithoutFullErrorPath(
0371:                            MAINTAINABLE_ERROR_PREFIX + propertyName,
0372:                            errorConstant, parameters);
0373:                }
0374:            }
0375:
0376:            /**
0377:             * Adds a property-specific error to the global errors list, with the DD short label as the single argument.
0378:             * 
0379:             * @param propertyName - Property name of the element that is associated with the error. Used to mark the field as errored in
0380:             *        the UI.
0381:             * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
0382:             */
0383:            protected void putFieldErrorWithShortLabel(String propertyName,
0384:                    String errorConstant) {
0385:                String shortLabel = ddService.getAttributeShortLabel(boClass,
0386:                        propertyName);
0387:                putFieldError(propertyName, errorConstant, shortLabel);
0388:            }
0389:
0390:            /**
0391:             * 
0392:             * This method is a convenience method to add a property-specific document error to the global errors list. This method makes
0393:             * sure that the correct prefix is added to the property name so that it will display correctly on maintenance documents.
0394:             * 
0395:             * @param propertyName - Property name of the element that is associated with the error. Used to mark the field as errored in
0396:             *        the UI.
0397:             * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
0398:             * @param parameter - Single parameter value that can be used in the message so that you can display specific values to the
0399:             *        user.
0400:             * 
0401:             */
0402:            protected void putDocumentError(String propertyName,
0403:                    String errorConstant, String parameter) {
0404:                if (!errorAlreadyExists(DOCUMENT_ERROR_PREFIX + propertyName,
0405:                        errorConstant)) {
0406:                    GlobalVariables.getErrorMap().putError(
0407:                            DOCUMENT_ERROR_PREFIX + propertyName,
0408:                            errorConstant, parameter);
0409:                }
0410:            }
0411:
0412:            /**
0413:             * 
0414:             * This method is a convenience method to add a property-specific document error to the global errors list. This method makes
0415:             * sure that the correct prefix is added to the property name so that it will display correctly on maintenance documents.
0416:             * 
0417:             * @param propertyName - Property name of the element that is associated with the error. Used to mark the field as errored in
0418:             *        the UI.
0419:             * @param errorConstant - Error Constant that can be mapped to a resource for the actual text message.
0420:             * @param parameters - Array of String parameters that can be used in the message so that you can display specific values to the
0421:             *        user.
0422:             * 
0423:             */
0424:            protected void putDocumentError(String propertyName,
0425:                    String errorConstant, String[] parameters) {
0426:                GlobalVariables.getErrorMap().putError(
0427:                        DOCUMENT_ERROR_PREFIX + propertyName, errorConstant,
0428:                        parameters);
0429:            }
0430:
0431:            /**
0432:             * 
0433:             * Convenience method to determine whether the field already has the message indicated.
0434:             * 
0435:             * This is useful if you want to suppress duplicate error messages on the same field.
0436:             * 
0437:             * @param propertyName - propertyName you want to test on
0438:             * @param errorConstant - errorConstant you want to test
0439:             * @return returns True if the propertyName indicated already has the errorConstant indicated, false otherwise
0440:             * 
0441:             */
0442:            private boolean errorAlreadyExists(String propertyName,
0443:                    String errorConstant) {
0444:
0445:                if (GlobalVariables.getErrorMap().fieldHasMessage(propertyName,
0446:                        errorConstant)) {
0447:                    return true;
0448:                } else {
0449:                    return false;
0450:                }
0451:            }
0452:
0453:            /**
0454:             * 
0455:             * This method specifically doesn't put any prefixes before the error so that the developer can do things specific to the
0456:             * globals errors (like newDelegateChangeDocument errors)
0457:             * 
0458:             * @param propertyName
0459:             * @param errorConstant
0460:             */
0461:            protected void putGlobalsError(String propertyName,
0462:                    String errorConstant) {
0463:                if (!errorAlreadyExists(propertyName, errorConstant)) {
0464:                    GlobalVariables.getErrorMap().putErrorWithoutFullErrorPath(
0465:                            propertyName, errorConstant);
0466:                }
0467:            }
0468:
0469:            /**
0470:             * 
0471:             * This method specifically doesn't put any prefixes before the error so that the developer can do things specific to the
0472:             * globals errors (like newDelegateChangeDocument errors)
0473:             * 
0474:             * @param propertyName
0475:             * @param errorConstant
0476:             * @param parameter
0477:             */
0478:            protected void putGlobalsError(String propertyName,
0479:                    String errorConstant, String parameter) {
0480:                if (!errorAlreadyExists(propertyName, errorConstant)) {
0481:                    GlobalVariables.getErrorMap().putErrorWithoutFullErrorPath(
0482:                            propertyName, errorConstant, parameter);
0483:                }
0484:            }
0485:
0486:            /**
0487:             * 
0488:             * This method is used to deal with error paths that are not what we expect them to be. This method, along with
0489:             * resumeErrorPath() are used to temporarily clear the errorPath, and then return it to the original state after the rule is
0490:             * executed.
0491:             * 
0492:             * This method is called at the very beginning of rule enforcement and pulls a copy of the contents of the errorPath ArrayList
0493:             * to a local arrayList for temporary storage.
0494:             * 
0495:             */
0496:            protected void clearErrorPath() {
0497:
0498:                // add all the items from the global list to the local list
0499:                priorErrorPath.addAll(GlobalVariables.getErrorMap()
0500:                        .getErrorPath());
0501:
0502:                // clear the global list
0503:                GlobalVariables.getErrorMap().getErrorPath().clear();
0504:
0505:            }
0506:
0507:            /**
0508:             * 
0509:             * This method is used to deal with error paths that are not what we expect them to be. This method, along with clearErrorPath()
0510:             * are used to temporarily clear the errorPath, and then return it to the original state after the rule is executed.
0511:             * 
0512:             * This method is called at the very end of the rule enforcement, and returns the temporarily stored copy of the errorPath to
0513:             * the global errorPath, so that no other classes are interrupted.
0514:             * 
0515:             */
0516:            protected void resumeErrorPath() {
0517:                // revert the global errorPath back to what it was when we entered this
0518:                // class
0519:                GlobalVariables.getErrorMap().getErrorPath().addAll(
0520:                        priorErrorPath);
0521:            }
0522:
0523:            /**
0524:             * 
0525:             * This method executes the DataDictionary Validation against the document.
0526:             * 
0527:             * @param document
0528:             * @return true if it passes DD validation, false otherwise
0529:             */
0530:            protected boolean dataDictionaryValidate(
0531:                    MaintenanceDocument document) {
0532:
0533:                LOG.debug("MaintenanceDocument validation beginning");
0534:
0535:                // explicitly put the errorPath that the dictionaryValidationService requires
0536:                GlobalVariables.getErrorMap().addToErrorPath(
0537:                        "document.newMaintainableObject");
0538:
0539:                // document must have a newMaintainable object
0540:                Maintainable newMaintainable = document
0541:                        .getNewMaintainableObject();
0542:                if (newMaintainable == null) {
0543:                    GlobalVariables.getErrorMap().removeFromErrorPath(
0544:                            "document.newMaintainableObject");
0545:                    throw new ValidationException(
0546:                            "Maintainable object from Maintenance Document '"
0547:                                    + document.getDocumentTitle()
0548:                                    + "' is null, unable to proceed.");
0549:                }
0550:
0551:                // document's newMaintainable must contain an object (ie, not null)
0552:                PersistableBusinessObject businessObject = newMaintainable
0553:                        .getBusinessObject();
0554:                if (businessObject == null) {
0555:                    GlobalVariables.getErrorMap().removeFromErrorPath(
0556:                            "document.newMaintainableObject.");
0557:                    throw new ValidationException(
0558:                            "Maintainable's component business object is null.");
0559:                }
0560:
0561:                // run required check from maintenance data dictionary
0562:                maintDocDictionaryService
0563:                        .validateMaintenanceRequiredFields(document);
0564:
0565:                //check for duplicate entries in collections if necessary
0566:                maintDocDictionaryService
0567:                        .validateMaintainableCollectionsForDuplicateEntries(document);
0568:
0569:                // run the DD DictionaryValidation (non-recursive)
0570:                dictionaryValidationService.validateBusinessObject(
0571:                        businessObject, false);
0572:
0573:                // do default (ie, mandatory) existence checks
0574:                dictionaryValidationService
0575:                        .validateDefaultExistenceChecks(businessObject);
0576:
0577:                // do apc checks
0578:                dictionaryValidationService.validateApcRules(businessObject);
0579:
0580:                // explicitly remove the errorPath we've added
0581:                GlobalVariables.getErrorMap().removeFromErrorPath(
0582:                        "document.newMaintainableObject");
0583:
0584:                LOG.debug("MaintenanceDocument validation ending");
0585:                return true;
0586:            }
0587:
0588:            /**
0589:             * 
0590:             * This method checks the two major cases that may violate primary key integrity.
0591:             * 
0592:             * 1. Disallow changing of the primary keys on an EDIT maintenance document. Other fields can be changed, but once the primary
0593:             * keys have been set, they are permanent.
0594:             * 
0595:             * 2. Disallow creating a new object whose primary key values are already present in the system on a CREATE NEW maintenance
0596:             * document.
0597:             * 
0598:             * This method also will add new Errors to the Global Error Map.
0599:             * 
0600:             * @param document - The Maintenance Document being tested.
0601:             * @return Returns false if either test failed, otherwise returns true.
0602:             * 
0603:             */
0604:            private boolean primaryKeyCheck(MaintenanceDocument document) {
0605:
0606:                // default to success if no failures
0607:                boolean success = true;
0608:                Class boClass = document.getNewMaintainableObject()
0609:                        .getBoClass();
0610:
0611:                PersistableBusinessObject oldBo = document
0612:                        .getOldMaintainableObject().getBusinessObject();
0613:                PersistableBusinessObject newBo = document
0614:                        .getNewMaintainableObject().getBusinessObject();
0615:
0616:                // We dont do primaryKeyChecks on Global Business Object maintenance documents. This is
0617:                // because it doesnt really make any sense to do so, given the behavior of Globals. When a
0618:                // Global Document completes, it will update or create a new record for each BO in the list.
0619:                // As a result, there's no problem with having existing BO records in the system, they will
0620:                // simply get updated.
0621:                if (newBo instanceof  GlobalBusinessObject) {
0622:                    return success;
0623:                }
0624:
0625:                // fail and complain if the person has changed the primary keys on
0626:                // an EDIT maintenance document.
0627:                if (document.isEdit()) {
0628:                    if (!ObjectUtils.equalByKeys(oldBo, newBo)) { // this is a very handy utility on our ObjectUtils
0629:
0630:                        // add a complaint to the errors
0631:                        putDocumentError(
0632:                                RiceConstants.DOCUMENT_ERRORS,
0633:                                RiceKeyConstants.ERROR_DOCUMENT_MAINTENANCE_PRIMARY_KEYS_CHANGED_ON_EDIT,
0634:                                getHumanReadablePrimaryKeyFieldNames(boClass));
0635:                        success &= false;
0636:                    }
0637:                }
0638:
0639:                // fail and complain if the person has selected a new object with keys that already exist
0640:                // in the DB.
0641:                else if (document.isNew()) {
0642:
0643:                    // get a map of the pk field names and values
0644:                    Map newPkFields = persistenceService
0645:                            .getPrimaryKeyFieldValues(newBo);
0646:
0647:                    // TODO: Good suggestion from Aaron, dont bother checking the DB, if all of the
0648:                    // objects PK fields dont have values. If any are null or empty, then
0649:                    // we're done. The current way wont fail, but it will make a wasteful
0650:                    // DB call that may not be necessary, and we want to minimize these.
0651:
0652:                    // attempt to do a lookup, see if this object already exists by these Primary Keys
0653:                    PersistableBusinessObject testBo = boService
0654:                            .findByPrimaryKey(boClass, newPkFields);
0655:
0656:                    // if the retrieve was successful, then this object already exists, and we need
0657:                    // to complain
0658:                    if (testBo != null) {
0659:                        putDocumentError(
0660:                                RiceConstants.DOCUMENT_ERRORS,
0661:                                RiceKeyConstants.ERROR_DOCUMENT_MAINTENANCE_KEYS_ALREADY_EXIST_ON_CREATE_NEW,
0662:                                getHumanReadablePrimaryKeyFieldNames(boClass));
0663:                        success &= false;
0664:                    }
0665:                }
0666:                return success;
0667:            }
0668:
0669:            /**
0670:             * 
0671:             * This method creates a human-readable string of the class' primary key field names, as designated by the DataDictionary.
0672:             * 
0673:             * @param boClass
0674:             * @return
0675:             */
0676:            private String getHumanReadablePrimaryKeyFieldNames(Class boClass) {
0677:
0678:                String delim = "";
0679:                StringBuffer pkFieldNames = new StringBuffer();
0680:
0681:                // get a list of all the primary key field names, walk through them
0682:                List pkFields = persistenceStructureService
0683:                        .getPrimaryKeys(boClass);
0684:                for (Iterator iter = pkFields.iterator(); iter.hasNext();) {
0685:                    String pkFieldName = (String) iter.next();
0686:
0687:                    // use the DataDictionary service to translate field name into human-readable label
0688:                    String humanReadableFieldName = ddService
0689:                            .getAttributeLabel(boClass, pkFieldName);
0690:
0691:                    // append the next field
0692:                    pkFieldNames.append(delim + humanReadableFieldName);
0693:
0694:                    // separate names with commas after the first one
0695:                    if (delim.equalsIgnoreCase("")) {
0696:                        delim = ", ";
0697:                    }
0698:                }
0699:
0700:                return pkFieldNames.toString();
0701:            }
0702:
0703:            /**
0704:             * This method enforces all business rules that are common to all maintenance documents which must be tested before doing an
0705:             * approval.
0706:             * 
0707:             * It can be overloaded in special cases where a MaintenanceDocument has very special needs that would be contrary to what is
0708:             * enforced here.
0709:             * 
0710:             * @param document - a populated MaintenanceDocument instance
0711:             * @return true if the document can be approved, false if not
0712:             */
0713:            protected boolean processGlobalApproveDocumentBusinessRules(
0714:                    MaintenanceDocument document) {
0715:                boolean success = true;
0716:
0717:                // enforce authorization restrictions on fields
0718:                success &= checkAuthorizationRestrictions(document);
0719:                return success;
0720:            }
0721:
0722:            /**
0723:             * 
0724:             * This method enforces all business rules that are common to all maintenance documents which must be tested before doing a
0725:             * route.
0726:             * 
0727:             * It can be overloaded in special cases where a MaintenanceDocument has very special needs that would be contrary to what is
0728:             * enforced here.
0729:             * 
0730:             * @param document - a populated MaintenanceDocument instance
0731:             * @return true if the document can be routed, false if not
0732:             */
0733:            protected boolean processGlobalRouteDocumentBusinessRules(
0734:                    MaintenanceDocument document) {
0735:
0736:                boolean success = true;
0737:
0738:                // require a document description field
0739:                success &= checkEmptyDocumentField(
0740:                        "documentHeader.financialDocumentDescription", document
0741:                                .getDocumentHeader()
0742:                                .getFinancialDocumentDescription(),
0743:                        "Description");
0744:
0745:                // enforce authorization restrictions on fields
0746:                success &= checkAuthorizationRestrictions(document);
0747:                return success;
0748:            }
0749:
0750:            /**
0751:             * 
0752:             * This method enforces all business rules that are common to all maintenance documents which must be tested before doing a
0753:             * save.
0754:             * 
0755:             * It can be overloaded in special cases where a MaintenanceDocument has very special needs that would be contrary to what is
0756:             * enforced here.
0757:             * 
0758:             * Note that although this method returns a true or false to indicate whether the save should happen or not, this result may not
0759:             * be followed by the calling method. In other words, the boolean result will likely be ignored, and the document saved,
0760:             * regardless.
0761:             * 
0762:             * @param document - a populated MaintenanceDocument instance
0763:             * @return true if all business rules succeed, false if not
0764:             */
0765:            protected boolean processGlobalSaveDocumentBusinessRules(
0766:                    MaintenanceDocument document) {
0767:
0768:                // default to success
0769:                boolean success = true;
0770:
0771:                // do generic checks that impact primary key violations
0772:                primaryKeyCheck(document);
0773:
0774:                // this is happening only on the processSave, since a Save happens in both the
0775:                // Route and Save events.
0776:                this .dataDictionaryValidate(document);
0777:
0778:                // enforce authorization restrictions on fields
0779:                checkAuthorizationRestrictions(document);
0780:
0781:                return success;
0782:            }
0783:
0784:            /**
0785:             * This method should be overridden to provide custom rules for processing document saving
0786:             * 
0787:             * @param document
0788:             * @return boolean
0789:             */
0790:            protected boolean processCustomSaveDocumentBusinessRules(
0791:                    MaintenanceDocument document) {
0792:                return true;
0793:            }
0794:
0795:            /**
0796:             * 
0797:             * This method should be overridden to provide custom rules for processing document routing
0798:             * 
0799:             * @param document
0800:             * @return boolean
0801:             */
0802:            protected boolean processCustomRouteDocumentBusinessRules(
0803:                    MaintenanceDocument document) {
0804:                return true;
0805:            }
0806:
0807:            /**
0808:             * This method should be overridden to provide custom rules for processing document approval.
0809:             * 
0810:             * @param document
0811:             * @return booelan
0812:             */
0813:            protected boolean processCustomApproveDocumentBusinessRules(
0814:                    MaintenanceDocument document) {
0815:                return true;
0816:            }
0817:
0818:            // Document Validation Helper Methods
0819:
0820:            /**
0821:             * 
0822:             * This method checks to see if the document is in a state that it can be saved without causing exceptions.
0823:             * 
0824:             * Note that Business Rules are NOT enforced here, only validity checks.
0825:             * 
0826:             * This method will only return false if the document is in such a state that routing it will cause RunTimeExceptions.
0827:             * 
0828:             * @param maintenanceDocument - a populated MaintenaceDocument instance.
0829:             * @return boolean - returns true unless the object is in an invalid state.
0830:             * 
0831:             */
0832:            protected boolean isDocumentValidForSave(
0833:                    MaintenanceDocument maintenanceDocument) {
0834:
0835:                boolean success = true;
0836:
0837:                success &= super .isDocumentOverviewValid(maintenanceDocument);
0838:                success &= validateDocumentStructure((Document) maintenanceDocument);
0839:                success &= validateMaintenanceDocument(maintenanceDocument);
0840:                success &= validateGlobalBusinessObjectPersistable(maintenanceDocument);
0841:                return success;
0842:            }
0843:
0844:            /**
0845:             * 
0846:             * This method makes sure the document itself is valid, and has the necessary fields populated to be routable.
0847:             * 
0848:             * This is not a business rules test, rather its a structure test to make sure that the document will not cause exceptions
0849:             * before routing.
0850:             * 
0851:             * @param document - document to be tested
0852:             * @return false if the document is missing key values, true otherwise
0853:             */
0854:            protected boolean validateDocumentStructure(Document document) {
0855:                boolean success = true;
0856:
0857:                // document must have a populated documentNumber
0858:                String documentHeaderId = document.getDocumentNumber();
0859:                if (documentHeaderId == null
0860:                        || StringUtils.isEmpty(documentHeaderId)) {
0861:                    throw new ValidationException(
0862:                            "Document has no document number, unable to proceed.");
0863:                }
0864:
0865:                return success;
0866:            }
0867:
0868:            /**
0869:             * 
0870:             * This method checks to make sure the document is a valid maintenanceDocument, and has the necessary values populated such that
0871:             * it will not cause exceptions in later routing or business rules testing.
0872:             * 
0873:             * This is not a business rules test.
0874:             * 
0875:             * @param maintenanceDocument - document to be tested
0876:             * @return whether maintenance doc passes
0877:             * @throws ValidationException
0878:             */
0879:            protected boolean validateMaintenanceDocument(
0880:                    MaintenanceDocument maintenanceDocument) {
0881:                boolean success = true;
0882:                Maintainable newMaintainable = maintenanceDocument
0883:                        .getNewMaintainableObject();
0884:
0885:                // document must have a newMaintainable object
0886:                if (newMaintainable == null) {
0887:                    throw new ValidationException(
0888:                            "Maintainable object from Maintenance Document '"
0889:                                    + maintenanceDocument.getDocumentTitle()
0890:                                    + "' is null, unable to proceed.");
0891:                }
0892:
0893:                // document's newMaintainable must contain an object (ie, not null)
0894:                if (newMaintainable.getBusinessObject() == null) {
0895:                    throw new ValidationException(
0896:                            "Maintainable's component business object is null.");
0897:                }
0898:
0899:                // document's newMaintainable must contain a valid BusinessObject descendent
0900:                if (!PersistableBusinessObject.class
0901:                        .isAssignableFrom(newMaintainable.getBoClass())) {
0902:                    throw new ValidationException(
0903:                            "Maintainable's component object is not descended from BusinessObject.");
0904:                }
0905:                return success;
0906:            }
0907:
0908:            /**
0909:             * 
0910:             * This method checks whether this maint doc contains Global Business Objects, and if so, whether the GBOs are in a persistable
0911:             * state. This will return false if this method determines that the GBO will cause a SQL Exception when the document is
0912:             * persisted.
0913:             * 
0914:             * @param document
0915:             * @return False when the method determines that the contained Global Business Object will cause a SQL Exception, and the
0916:             *         document should not be saved. It will return True otherwise.
0917:             * 
0918:             */
0919:            protected boolean validateGlobalBusinessObjectPersistable(
0920:                    MaintenanceDocument document) {
0921:                boolean success = true;
0922:
0923:                if (document.getNewMaintainableObject() == null) {
0924:                    return success;
0925:                }
0926:                if (document.getNewMaintainableObject().getBusinessObject() == null) {
0927:                    return success;
0928:                }
0929:                if (!(document.getNewMaintainableObject().getBusinessObject() instanceof  GlobalBusinessObject)) {
0930:                    return success;
0931:                }
0932:
0933:                PersistableBusinessObject bo = (PersistableBusinessObject) document
0934:                        .getNewMaintainableObject().getBusinessObject();
0935:                GlobalBusinessObject gbo = (GlobalBusinessObject) bo;
0936:                return gbo.isPersistable();
0937:            }
0938:
0939:            /**
0940:             * 
0941:             * This method tests to make sure the MaintenanceDocument passed in is based on the class you are expecting.
0942:             * 
0943:             * It does this based on the NewMaintainableObject of the MaintenanceDocument.
0944:             * 
0945:             * @param document - MaintenanceDocument instance you want to test
0946:             * @param clazz - class you are expecting the MaintenanceDocument to be based on
0947:             * @return true if they match, false if not
0948:             * 
0949:             */
0950:            protected boolean isCorrectMaintenanceClass(
0951:                    MaintenanceDocument document, Class clazz) {
0952:
0953:                // disallow null arguments
0954:                if (document == null || clazz == null) {
0955:                    throw new IllegalArgumentException(
0956:                            "Null arguments were passed in.");
0957:                }
0958:
0959:                // compare the class names
0960:                if (clazz.toString().equals(
0961:                        document.getNewMaintainableObject().getBoClass()
0962:                                .toString())) {
0963:                    return true;
0964:                } else {
0965:                    return false;
0966:                }
0967:            }
0968:
0969:            /**
0970:             * 
0971:             * This method accepts an object, and attempts to determine whether it is empty by this method's definition.
0972:             * 
0973:             * OBJECT RESULT null false empty-string false whitespace false otherwise true
0974:             * 
0975:             * If the result is false, it will add an object field error to the Global Errors.
0976:             * 
0977:             * @param valueToTest - any object to test, usually a String
0978:             * @param propertyName - the name of the property being tested
0979:             * @return true or false, by the description above
0980:             * 
0981:             */
0982:            protected boolean checkEmptyBOField(String propertyName,
0983:                    Object valueToTest, String parameter) {
0984:
0985:                boolean success = true;
0986:
0987:                success = checkEmptyValue(valueToTest);
0988:
0989:                // if failed, then add a field error
0990:                if (!success) {
0991:                    putFieldError(propertyName,
0992:                            RiceKeyConstants.ERROR_REQUIRED, parameter);
0993:                }
0994:
0995:                return success;
0996:            }
0997:
0998:            /**
0999:             * 
1000:             * This method accepts document field (such as , and attempts to determine whether it is empty by this method's definition.
1001:             * 
1002:             * OBJECT RESULT null false empty-string false whitespace false otherwise true
1003:             * 
1004:             * If the result is false, it will add document field error to the Global Errors.
1005:             * 
1006:             * @param valueToTest - any object to test, usually a String
1007:             * @param propertyName - the name of the property being tested
1008:             * @return true or false, by the description above
1009:             * 
1010:             */
1011:            protected boolean checkEmptyDocumentField(String propertyName,
1012:                    Object valueToTest, String parameter) {
1013:                boolean success = true;
1014:                success = checkEmptyValue(valueToTest);
1015:                if (!success) {
1016:                    putDocumentError(propertyName,
1017:                            RiceKeyConstants.ERROR_REQUIRED, parameter);
1018:                }
1019:                return success;
1020:            }
1021:
1022:            /**
1023:             * 
1024:             * This method accepts document field (such as , and attempts to determine whether it is empty by this method's definition.
1025:             * 
1026:             * OBJECT RESULT null false empty-string false whitespace false otherwise true
1027:             * 
1028:             * It will the result as a boolean
1029:             * 
1030:             * @param valueToTest - any object to test, usually a String
1031:             * 
1032:             */
1033:            protected boolean checkEmptyValue(Object valueToTest) {
1034:                boolean success = true;
1035:
1036:                // if its not a string, only fail if its a null object
1037:                if (valueToTest == null) {
1038:                    success = false;
1039:                } else {
1040:                    // test for null, empty-string, or whitespace if its a string
1041:                    if (valueToTest instanceof  String) {
1042:                        if (StringUtils.isBlank((String) valueToTest)) {
1043:                            success = false;
1044:                        }
1045:                    }
1046:                }
1047:
1048:                return success;
1049:            }
1050:
1051:            /**
1052:             * 
1053:             * This method is used during debugging to dump the contents of the error map, including the key names. It is not used by the
1054:             * application in normal circumstances at all.
1055:             * 
1056:             */
1057:            private void showErrorMap() {
1058:
1059:                if (GlobalVariables.getErrorMap().isEmpty()) {
1060:                    return;
1061:                }
1062:
1063:                for (Iterator i = GlobalVariables.getErrorMap().entrySet()
1064:                        .iterator(); i.hasNext();) {
1065:                    Map.Entry e = (Map.Entry) i.next();
1066:
1067:                    TypedArrayList errorList = (TypedArrayList) e.getValue();
1068:                    for (Iterator j = errorList.iterator(); j.hasNext();) {
1069:                        ErrorMessage em = (ErrorMessage) j.next();
1070:
1071:                        if (em.getMessageParameters() == null) {
1072:                            LOG.error(e.getKey().toString() + " = "
1073:                                    + em.getErrorKey());
1074:                        } else {
1075:                            LOG.error(e.getKey().toString() + " = "
1076:                                    + em.getErrorKey() + " : "
1077:                                    + em.getMessageParameters().toString());
1078:                        }
1079:                    }
1080:                }
1081:
1082:            }
1083:
1084:            /**
1085:             * @see org.kuali.core.maintenance.rules.MaintenanceDocumentRule#setupBaseConvenienceObjects(MaintenanceDocument)
1086:             */
1087:            public void setupBaseConvenienceObjects(MaintenanceDocument document) {
1088:
1089:                // setup oldAccount convenience objects, make sure all possible sub-objects are populated
1090:                oldBo = (PersistableBusinessObject) document
1091:                        .getOldMaintainableObject().getBusinessObject();
1092:                if (oldBo != null) {
1093:                    oldBo.refreshNonUpdateableReferences();
1094:                }
1095:
1096:                // setup newAccount convenience objects, make sure all possible sub-objects are populated
1097:                newBo = (PersistableBusinessObject) document
1098:                        .getNewMaintainableObject().getBusinessObject();
1099:                newBo.refreshNonUpdateableReferences();
1100:
1101:                boClass = document.getNewMaintainableObject().getBoClass();
1102:
1103:                // call the setupConvenienceObjects in the subclass, if a subclass exists
1104:                setupConvenienceObjects();
1105:            }
1106:
1107:            public void setupConvenienceObjects() {
1108:                // should always be overriden by subclass
1109:            }
1110:
1111:            /**
1112:             * 
1113:             * This method ensures that any fields that are restricted by the Authorization system in the system are also enforced on the
1114:             * back-end, otherwise form manipulation could bypass authorization rules.
1115:             * 
1116:             * This method will add errors to the Global ErrorMap if any problems are encountered.
1117:             * 
1118:             * @param document - the maintenance document being evaluated
1119:             * @return true if no failures occurred, false otherwise
1120:             */
1121:            protected boolean checkAuthorizationRestrictions(
1122:                    MaintenanceDocument document) {
1123:
1124:                // Note that this method does what may at first appear to be a highly efficient loading
1125:                // of the document that is already loaded, and compares against that. This is done to handle
1126:                // situations where someone along the chain of approvers has rights to modify some fields, but
1127:                // later approvers do not have similar rights. This is how we've made sure that this person,
1128:                // only during this modification of the document, has not changed any fields on the newBo side,
1129:                // without wiring something into the Struts that somehow tells us that a field was modified.
1130:                // There may indeed be better ways to do this, but make sure you're solving all the problems
1131:                // here, including ones like this: KULCOA-924, KULCOA-884, etc
1132:
1133:                boolean success = true;
1134:                boolean changed = false;
1135:
1136:                boolean isInitiator = false;
1137:                boolean isApprover = false;
1138:
1139:                Object oldValue = null;
1140:                Object newValue = null;
1141:                Object savedValue = null;
1142:
1143:                KualiWorkflowDocument workflowDocument = null;
1144:                UniversalUser user = GlobalVariables.getUserSession()
1145:                        .getUniversalUser();
1146:                try {
1147:                    workflowDocument = getWorkflowDocumentService()
1148:                            .createWorkflowDocument(
1149:                                    Long.valueOf(document.getDocumentNumber()),
1150:                                    user);
1151:                } catch (WorkflowException e) {
1152:                    throw new UnknownDocumentIdException(
1153:                            "no document found for documentHeaderId '"
1154:                                    + document.getDocumentNumber() + "'", e);
1155:                }
1156:                if (user.getPersonUserIdentifier().equalsIgnoreCase(
1157:                        workflowDocument.getInitiatorNetworkId())) {
1158:                    // if these are the same person then we know it is the initiator
1159:                    isInitiator = true;
1160:                } else if (workflowDocument.isApprovalRequested()) {
1161:                    isApprover = true;
1162:                }
1163:
1164:                // get the correct documentAuthorizer for this document
1165:                MaintenanceDocumentAuthorizer documentAuthorizer = (MaintenanceDocumentAuthorizer) documentAuthorizationService
1166:                        .getDocumentAuthorizer(document);
1167:
1168:                // get a new instance of MaintenanceDocumentAuthorizations for this context
1169:                MaintenanceDocumentAuthorizations auths = documentAuthorizer
1170:                        .getFieldAuthorizations(document, user);
1171:
1172:                // load a temp copy of the document from the DB to compare to for changes
1173:                MaintenanceDocument savedDoc = null;
1174:                Maintainable savedNewMaintainable = null;
1175:                PersistableBusinessObject savedNewBo = null;
1176:
1177:                if (isApprover) {
1178:                    try {
1179:                        DocumentService docService = KNSServiceLocator
1180:                                .getDocumentService();
1181:                        savedDoc = (MaintenanceDocument) docService
1182:                                .getByDocumentHeaderId(document
1183:                                        .getDocumentNumber());
1184:                    } catch (WorkflowException e) {
1185:                        throw new RuntimeException(
1186:                                "A WorkflowException was thrown which prevented the loading of "
1187:                                        + "the comparison document ("
1188:                                        + document.getDocumentNumber() + ")", e);
1189:                    }
1190:
1191:                    // attempt to retrieve the BO, but leave it blank if it or any of the objects on the path
1192:                    // to it are blank
1193:                    if (savedDoc != null) {
1194:                        savedNewMaintainable = savedDoc
1195:                                .getNewMaintainableObject();
1196:                        if (savedNewMaintainable != null) {
1197:                            savedNewBo = savedNewMaintainable
1198:                                    .getBusinessObject();
1199:                        }
1200:                    }
1201:                }
1202:
1203:                // setup in-loop members
1204:                FieldAuthorization fieldAuthorization = null;
1205:
1206:                // walk through all the restrictions
1207:                Collection restrictedFields = auths.getAuthFieldNames();
1208:                for (Iterator iter = restrictedFields.iterator(); iter
1209:                        .hasNext();) {
1210:                    String fieldName = (String) iter.next();
1211:
1212:                    // get the specific field authorization structure
1213:                    fieldAuthorization = auths
1214:                            .getAuthFieldAuthorization(fieldName);
1215:
1216:                    // if there are any restrictions, then enforce them
1217:                    if (fieldAuthorization.isRestricted()) {
1218:                        // reset the changed flag
1219:                        changed = false;
1220:
1221:                        // new value should always be the same regardles of who is
1222:                        // making the request
1223:                        newValue = ObjectUtils.getNestedValue(newBo, fieldName);
1224:
1225:                        // first we need to handle the case of edit doc && initiator
1226:                        if (isInitiator && document.isEdit()) {
1227:                            // old value must equal new value
1228:                            oldValue = ObjectUtils.getNestedValue(oldBo,
1229:                                    fieldName);
1230:                        } else if (isApprover && savedNewBo != null) {
1231:                            oldValue = ObjectUtils.getNestedValue(savedNewBo,
1232:                                    fieldName);
1233:                        }
1234:
1235:                        // check to make sure nothing has changed
1236:                        if (oldValue == null && newValue == null) {
1237:                            changed = false;
1238:                        } else if ((oldValue == null && newValue != null)
1239:                                || (oldValue != null && newValue == null)) {
1240:                            changed = true;
1241:                        } else if (oldValue != null && newValue != null) {
1242:                            if (!oldValue.equals(newValue)) {
1243:                                changed = true;
1244:                            }
1245:                        }
1246:
1247:                        // if changed and a NEW doc, but the new value is the default value, then let it go
1248:                        // we dont allow changing to default values for EDIT docs though, only NEW
1249:                        if (changed && document.isNew()) {
1250:                            String defaultValue = maintDocDictionaryService
1251:                                    .getFieldDefaultValue(document
1252:                                            .getNewMaintainableObject()
1253:                                            .getBoClass(), fieldName);
1254:
1255:                            // get the string value of newValue
1256:                            String newStringValue = newValue.toString();
1257:
1258:                            // if the newValue is the default value, then ignore
1259:                            if (newStringValue.equalsIgnoreCase(defaultValue)) {
1260:                                changed = false;
1261:                            }
1262:                        }
1263:
1264:                        // if anything has changed, complain
1265:                        if (changed) {
1266:                            String humanReadableFieldName = ddService
1267:                                    .getAttributeLabel(document
1268:                                            .getNewMaintainableObject()
1269:                                            .getBoClass(), fieldName);
1270:                            putFieldError(
1271:                                    fieldName,
1272:                                    RiceKeyConstants.ERROR_DOCUMENT_AUTHORIZATION_RESTRICTED_FIELD_CHANGED,
1273:                                    humanReadableFieldName);
1274:                            success &= false;
1275:                        }
1276:                    }
1277:                }
1278:                return success;
1279:            }
1280:
1281:            /**
1282:             * 
1283:             * This method checks to make sure that if the foreign-key fields for the given reference attributes have any fields filled out,
1284:             * that all fields are filled out.
1285:             * 
1286:             * If any are filled out, but all are not, it will return false and add a global error message about the problem.
1287:             * 
1288:             * @param referenceName - The name of the reference object, whose foreign-key fields must be all-or-none filled out.
1289:             * 
1290:             * @return true if this is the case, false if not
1291:             * 
1292:             */
1293:            protected boolean checkForPartiallyFilledOutReferenceForeignKeys(
1294:                    String referenceName) {
1295:
1296:                boolean success;
1297:
1298:                ForeignKeyFieldsPopulationState fkFieldsState;
1299:                fkFieldsState = persistenceStructureService
1300:                        .getForeignKeyFieldsPopulationState(newBo,
1301:                                referenceName);
1302:
1303:                // determine result
1304:                if (fkFieldsState.isAnyFieldsPopulated()
1305:                        && !fkFieldsState.isAllFieldsPopulated()) {
1306:                    success = false;
1307:                } else {
1308:                    success = true;
1309:                }
1310:
1311:                // add errors if appropriate
1312:                if (!success) {
1313:
1314:                    // get the full set of foreign-keys
1315:                    List fKeys = new ArrayList(persistenceStructureService
1316:                            .getForeignKeysForReference(newBo.getClass(),
1317:                                    referenceName).keySet());
1318:                    String fKeysReadable = consolidateFieldNames(fKeys, ", ")
1319:                            .toString();
1320:
1321:                    // walk through the missing fields
1322:                    for (Iterator iter = fkFieldsState
1323:                            .getUnpopulatedFieldNames().iterator(); iter
1324:                            .hasNext();) {
1325:                        String fieldName = (String) iter.next();
1326:
1327:                        // get the human-readable name
1328:                        String fieldNameReadable = ddService.getAttributeLabel(
1329:                                newBo.getClass(), fieldName);
1330:
1331:                        // add a field error
1332:                        putFieldError(
1333:                                fieldName,
1334:                                RiceKeyConstants.ERROR_DOCUMENT_MAINTENANCE_PARTIALLY_FILLED_OUT_REF_FKEYS,
1335:                                new String[] { fieldNameReadable, fKeysReadable });
1336:                    }
1337:                }
1338:
1339:                return success;
1340:            }
1341:
1342:            /**
1343:             * 
1344:             * This method is a shallow inverse wrapper around applyApcRule, it simply reverses the return value, for better readability in
1345:             * an if test.
1346:             * 
1347:             * This method applies an APC rule based on the values provided.
1348:             * 
1349:             * It will throw an ApplicationParameterException if the APC Group and Parm do not exist in the system.
1350:             * 
1351:             * @param apcGroupName - The script or group name in the APC system. If the value is null or blank, an IllegalArgumentException
1352:             *        will be thrown.
1353:             * @param parameterName - The name of the parm/rule in the APC system. If the value is null or blank, an IllegalArgumentException
1354:             *        will be thrown.
1355:             * @param valueToTest - The String value to test against the APC rule. The value may be null or blank without throwing an error,
1356:             *        but the rule will likely fail if null or blank.
1357:             * @return True if the rule fails, False if the rule passes.
1358:             * 
1359:             */
1360:            protected boolean apcRuleFails(String parameterNamespace,
1361:                    String parameterDetailTypeCode, String parameterName,
1362:                    String valueToTest) {
1363:                if (applyApcRule(parameterNamespace, parameterDetailTypeCode,
1364:                        parameterName, valueToTest) == false) {
1365:                    return true;
1366:                }
1367:                return false;
1368:            }
1369:
1370:            /**
1371:             * 
1372:             * This method applies an APC rule based on the values provided.
1373:             * 
1374:             * It will throw an ApplicationParameterException if the APC Group and Parm do not exist in the system.
1375:             * 
1376:             * @param apcGroupName - The script or group name in the APC system. If the value is null or blank, an IllegalArgumentException
1377:             *        will be thrown.
1378:             * @param parameterName - The name of the parm/rule in the APC system. If the value is null or blank, an IllegalArgumentException
1379:             *        will be thrown.
1380:             * @param valueToTest - The String value to test against the APC rule. The value may be null or blank without throwing an error,
1381:             *        but the rule will likely fail if null or blank.
1382:             * @return True if the rule passes, False if the rule fails.
1383:             * 
1384:             */
1385:            protected boolean applyApcRule(String parameterNamespace,
1386:                    String parameterDetailTypeCode, String parameterName,
1387:                    String valueToTest) {
1388:
1389:                // default to success
1390:                boolean success = true;
1391:
1392:                // apply the rule, see if it fails
1393:                if (!configService.evaluateConstrainedValue(parameterNamespace,
1394:                        parameterDetailTypeCode, parameterName, valueToTest)) {
1395:                    success = false;
1396:                }
1397:
1398:                return success;
1399:            }
1400:
1401:            /**
1402:             * 
1403:             * This method turns a list of field property names, into a delimited string of the human-readable names.
1404:             * 
1405:             * @param fieldNames - List of fieldNames
1406:             * @return A filled StringBuffer ready to go in an error message
1407:             * 
1408:             */
1409:            private StringBuffer consolidateFieldNames(List fieldNames,
1410:                    String delimiter) {
1411:
1412:                StringBuffer sb = new StringBuffer();
1413:
1414:                // setup some vars
1415:                boolean firstPass = true;
1416:                String delim = "";
1417:
1418:                // walk through the list
1419:                for (Iterator iter = fieldNames.iterator(); iter.hasNext();) {
1420:                    String fieldName = (String) iter.next();
1421:
1422:                    // get the human-readable name
1423:                    // add the new one, with the appropriate delimiter
1424:                    sb.append(delim
1425:                            + ddService.getAttributeLabel(newBo.getClass(),
1426:                                    fieldName));
1427:
1428:                    // after the first item, start using a delimiter
1429:                    if (firstPass) {
1430:                        delim = delimiter;
1431:                        firstPass = false;
1432:                    }
1433:                }
1434:
1435:                return sb;
1436:            }
1437:
1438:            /**
1439:             * 
1440:             * This method translates the passed in field name into a human-readable attribute label.
1441:             * 
1442:             * It assumes the existing newBO's class as the class to examine the fieldName for.
1443:             * 
1444:             * @param fieldName The fieldName you want a human-readable label for.
1445:             * @return A human-readable label, pulled from the DataDictionary.
1446:             * 
1447:             */
1448:            protected String getFieldLabel(String fieldName) {
1449:                return ddService.getAttributeLabel(newBo.getClass(), fieldName)
1450:                        + "("
1451:                        + ddService.getAttributeShortLabel(newBo.getClass(),
1452:                                fieldName) + ")";
1453:            }
1454:
1455:            /**
1456:             * 
1457:             * This method translates the passed in field name into a human-readable attribute label.
1458:             * 
1459:             * It assumes the existing newBO's class as the class to examine the fieldName for.
1460:             * 
1461:             * @param boClass The class to use in combination with the fieldName.
1462:             * @param fieldName The fieldName you want a human-readable label for.
1463:             * @return A human-readable label, pulled from the DataDictionary.
1464:             * 
1465:             */
1466:            protected String getFieldLabel(Class boClass, String fieldName) {
1467:                return ddService.getAttributeLabel(boClass, fieldName) + "("
1468:                        + ddService.getAttributeShortLabel(boClass, fieldName)
1469:                        + ")";
1470:            }
1471:
1472:            /**
1473:             * Gets the boDictionaryService attribute.
1474:             * 
1475:             * @return Returns the boDictionaryService.
1476:             */
1477:            protected final BusinessObjectDictionaryService getBoDictionaryService() {
1478:                return boDictionaryService;
1479:            }
1480:
1481:            /**
1482:             * Sets the boDictionaryService attribute value.
1483:             * 
1484:             * @param boDictionaryService The boDictionaryService to set.
1485:             */
1486:            public final void setBoDictionaryService(
1487:                    BusinessObjectDictionaryService boDictionaryService) {
1488:                this .boDictionaryService = boDictionaryService;
1489:            }
1490:
1491:            /**
1492:             * Gets the boService attribute.
1493:             * 
1494:             * @return Returns the boService.
1495:             */
1496:            protected final BusinessObjectService getBoService() {
1497:                return boService;
1498:            }
1499:
1500:            /**
1501:             * Sets the boService attribute value.
1502:             * 
1503:             * @param boService The boService to set.
1504:             */
1505:            public final void setBoService(BusinessObjectService boService) {
1506:                this .boService = boService;
1507:            }
1508:
1509:            /**
1510:             * Gets the configService attribute.
1511:             * 
1512:             * @return Returns the configService.
1513:             */
1514:            protected final KualiConfigurationService getConfigService() {
1515:                return configService;
1516:            }
1517:
1518:            /**
1519:             * Sets the configService attribute value.
1520:             * 
1521:             * @param configService The configService to set.
1522:             */
1523:            public final void setConfigService(
1524:                    KualiConfigurationService configService) {
1525:                this .configService = configService;
1526:            }
1527:
1528:            /**
1529:             * Gets the ddService attribute.
1530:             * 
1531:             * @return Returns the ddService.
1532:             */
1533:            protected final DataDictionaryService getDdService() {
1534:                return ddService;
1535:            }
1536:
1537:            /**
1538:             * Sets the ddService attribute value.
1539:             * 
1540:             * @param ddService The ddService to set.
1541:             */
1542:            public final void setDdService(DataDictionaryService ddService) {
1543:                this .ddService = ddService;
1544:            }
1545:
1546:            /**
1547:             * Gets the dictionaryValidationService attribute.
1548:             * 
1549:             * @return Returns the dictionaryValidationService.
1550:             */
1551:            protected final DictionaryValidationService getDictionaryValidationService() {
1552:                return dictionaryValidationService;
1553:            }
1554:
1555:            /**
1556:             * Sets the dictionaryValidationService attribute value.
1557:             * 
1558:             * @param dictionaryValidationService The dictionaryValidationService to set.
1559:             */
1560:            public final void setDictionaryValidationService(
1561:                    DictionaryValidationService dictionaryValidationService) {
1562:                this .dictionaryValidationService = dictionaryValidationService;
1563:            }
1564:
1565:            /**
1566:             * Gets the documentAuthorizationService attribute.
1567:             * 
1568:             * @return Returns the documentAuthorizationService.
1569:             */
1570:            protected final DocumentAuthorizationService getDocumentAuthorizationService() {
1571:                return documentAuthorizationService;
1572:            }
1573:
1574:            /**
1575:             * Sets the documentAuthorizationService attribute value.
1576:             * 
1577:             * @param documentAuthorizationService The documentAuthorizationService to set.
1578:             */
1579:            public final void setDocumentAuthorizationService(
1580:                    DocumentAuthorizationService documentAuthorizationService) {
1581:                this .documentAuthorizationService = documentAuthorizationService;
1582:            }
1583:
1584:            /**
1585:             * Gets the maintDocDictionaryService attribute.
1586:             * 
1587:             * @return Returns the maintDocDictionaryService.
1588:             */
1589:            protected final MaintenanceDocumentDictionaryService getMaintDocDictionaryService() {
1590:                return maintDocDictionaryService;
1591:            }
1592:
1593:            /**
1594:             * Sets the maintDocDictionaryService attribute value.
1595:             * 
1596:             * @param maintDocDictionaryService The maintDocDictionaryService to set.
1597:             */
1598:            public final void setMaintDocDictionaryService(
1599:                    MaintenanceDocumentDictionaryService maintDocDictionaryService) {
1600:                this .maintDocDictionaryService = maintDocDictionaryService;
1601:            }
1602:
1603:            /**
1604:             * Gets the newBo attribute.
1605:             * 
1606:             * @return Returns the newBo.
1607:             */
1608:            protected final PersistableBusinessObject getNewBo() {
1609:                return newBo;
1610:            }
1611:
1612:            protected void setNewBo(PersistableBusinessObject newBo) {
1613:                this .newBo = newBo;
1614:            }
1615:
1616:            /**
1617:             * Gets the oldBo attribute.
1618:             * 
1619:             * @return Returns the oldBo.
1620:             */
1621:            protected final PersistableBusinessObject getOldBo() {
1622:                return oldBo;
1623:            }
1624:
1625:            /**
1626:             * Gets the persistenceService attribute.
1627:             * 
1628:             * @return Returns the persistenceService.
1629:             */
1630:            protected final PersistenceService getPersistenceService() {
1631:                return persistenceService;
1632:            }
1633:
1634:            /**
1635:             * Sets the persistenceService attribute value.
1636:             * 
1637:             * @param persistenceService The persistenceService to set.
1638:             */
1639:            public final void setPersistenceService(
1640:                    PersistenceService persistenceService) {
1641:                this .persistenceService = persistenceService;
1642:            }
1643:
1644:            /**
1645:             * Gets the persistenceStructureService attribute.
1646:             * 
1647:             * @return Returns the persistenceStructureService.
1648:             */
1649:            protected final PersistenceStructureService getPersistenceStructureService() {
1650:                return persistenceStructureService;
1651:            }
1652:
1653:            /**
1654:             * Sets the persistenceStructureService attribute value.
1655:             * 
1656:             * @param persistenceStructureService The persistenceStructureService to set.
1657:             */
1658:            public final void setPersistenceStructureService(
1659:                    PersistenceStructureService persistenceStructureService) {
1660:                this .persistenceStructureService = persistenceStructureService;
1661:            }
1662:
1663:            /**
1664:             * Gets the workflowDocumentService attribute.
1665:             * 
1666:             * @return Returns the workflowDocumentService.
1667:             */
1668:            public WorkflowDocumentService getWorkflowDocumentService() {
1669:                return workflowDocumentService;
1670:            }
1671:
1672:            /**
1673:             * Sets the workflowDocumentService attribute value.
1674:             * 
1675:             * @param workflowDocumentService The workflowDocumentService to set.
1676:             */
1677:            public void setWorkflowDocumentService(
1678:                    WorkflowDocumentService workflowDocumentService) {
1679:                this .workflowDocumentService = workflowDocumentService;
1680:            }
1681:
1682:            public boolean processAddCollectionLineBusinessRules(
1683:                    MaintenanceDocument document, String collectionName,
1684:                    PersistableBusinessObject bo) {
1685:                LOG.debug("processAddCollectionLineBusinessRules");
1686:
1687:                // setup convenience pointers to the old & new bo
1688:                setupBaseConvenienceObjects(document);
1689:
1690:                // enforce authorization restrictions on fields
1691:                checkAuthorizationRestrictions(document);
1692:
1693:                // sanity check on the document object
1694:                this .validateMaintenanceDocument(document);
1695:
1696:                boolean success = true;
1697:                ErrorMap map = GlobalVariables.getErrorMap();
1698:                int errorCount = map.getErrorCount();
1699:                map.addToErrorPath(MAINTAINABLE_ERROR_PATH);
1700:                if (LOG.isDebugEnabled()) {
1701:                    LOG.debug("processAddCollectionLineBusinessRules - BO: "
1702:                            + bo);
1703:                    LOG.debug("Before Validate: " + map);
1704:                }
1705:                getBoDictionaryService().performForceUppercase(bo);
1706:                getMaintDocDictionaryService()
1707:                        .validateMaintainableCollectionsAddLineRequiredFields(
1708:                                document,
1709:                                document.getNewMaintainableObject()
1710:                                        .getBusinessObject(), collectionName);
1711:                String errorPath = RiceConstants.MAINTENANCE_ADD_PREFIX
1712:                        + collectionName;
1713:                map.addToErrorPath(errorPath);
1714:                getDictionaryValidationService().validateBusinessObject(bo,
1715:                        false);
1716:                success &= map.getErrorCount() == errorCount;
1717:                success &= validateDuplicateIdentifierInDataDictionary(
1718:                        document, collectionName, bo);
1719:                success &= processCustomAddCollectionLineBusinessRules(
1720:                        document, collectionName, bo);
1721:                map.removeFromErrorPath(errorPath);
1722:                map.removeFromErrorPath(MAINTAINABLE_ERROR_PATH);
1723:                if (LOG.isDebugEnabled()) {
1724:                    LOG.debug("After Validate: " + map);
1725:                    LOG
1726:                            .debug("processAddCollectionLineBusinessRules returning: "
1727:                                    + success);
1728:                }
1729:
1730:                return success;
1731:            }
1732:
1733:            /**
1734:             * This method validates that there should only exist one entry in the collection whose
1735:             * fields match the fields specified within the duplicateIdentificationFields in the 
1736:             * maintenance document data dictionary.
1737:             * If the duplicateIdentificationFields is not specified in the DD, by default it would
1738:             * allow the addition to happen and return true.
1739:             * It will return false if it fails the uniqueness validation.
1740:             * @param document
1741:             * @param collectionName
1742:             * @param bo
1743:             * @return
1744:             */
1745:            private boolean validateDuplicateIdentifierInDataDictionary(
1746:                    MaintenanceDocument document, String collectionName,
1747:                    PersistableBusinessObject bo) {
1748:                boolean valid = true;
1749:                PersistableBusinessObject maintBo = document
1750:                        .getNewMaintainableObject().getBusinessObject();
1751:                Collection maintCollection = (Collection) ObjectUtils
1752:                        .getPropertyValue(maintBo, collectionName);
1753:                List<String> duplicateIdentifier = document
1754:                        .getNewMaintainableObject()
1755:                        .getDuplicateIdentifierFieldsFromDataDictionary(
1756:                                document.getDocumentHeader()
1757:                                        .getWorkflowDocument()
1758:                                        .getDocumentType(), collectionName);
1759:                if (duplicateIdentifier.size() > 0) {
1760:                    List<String> existingIdentifierString = document
1761:                            .getNewMaintainableObject()
1762:                            .getMultiValueIdentifierList(maintCollection,
1763:                                    duplicateIdentifier);
1764:                    if (document.getNewMaintainableObject()
1765:                            .hasBusinessObjectExisted(bo,
1766:                                    existingIdentifierString,
1767:                                    duplicateIdentifier)) {
1768:                        valid = false;
1769:                        GlobalVariables.getErrorMap().putError(
1770:                                duplicateIdentifier.get(0),
1771:                                RiceKeyConstants.ERROR_DUPLICATE_ELEMENT,
1772:                                "entries in ",
1773:                                document.getDocumentHeader()
1774:                                        .getWorkflowDocument()
1775:                                        .getDocumentType());
1776:                    }
1777:                }
1778:                return valid;
1779:            }
1780:
1781:            public boolean processCustomAddCollectionLineBusinessRules(
1782:                    MaintenanceDocument document, String collectionName,
1783:                    PersistableBusinessObject line) {
1784:                return true;
1785:            }
1786:
1787:            public UniversalUserService getUniversalUserService() {
1788:                return universalUserService;
1789:            }
1790:
1791:            public void setUniversalUserService(
1792:                    UniversalUserService universalUserService) {
1793:                this .universalUserService = universalUserService;
1794:            }
1795:
1796:            public DateTimeService getDateTimeService() {
1797:                return KNSServiceLocator.getDateTimeService();
1798:            }
1799:
1800:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.