001: /*
002: * $Id: ModelService.java,v 1.9 2004/03/12 23:45:01 ajzeneski Exp $
003: *
004: * Copyright (c) 2001, 2002 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: *
024: */
025: package org.ofbiz.service;
026:
027: import java.util.ArrayList;
028: import java.util.Collection;
029: import java.util.HashMap;
030: import java.util.Iterator;
031: import java.util.LinkedList;
032: import java.util.List;
033: import java.util.Map;
034: import java.util.Set;
035: import java.util.TreeSet;
036:
037: import org.ofbiz.service.group.GroupModel;
038: import org.ofbiz.service.group.GroupServiceModel;
039: import org.ofbiz.service.group.ServiceGroupReader;
040: import org.ofbiz.base.util.Debug;
041: import org.ofbiz.base.util.GeneralException;
042: import org.ofbiz.base.util.ObjectType;
043: import org.ofbiz.base.util.OrderedSet;
044: import org.ofbiz.entity.GenericValue;
045: import org.ofbiz.security.Security;
046:
047: /**
048: * Generic Service Model Class
049: *
050: * @author <a href="mailto:jaz@ofbiz.org">Andy Zeneski</a>
051: * @author <a href="mailto:jonesde@ofbiz.org">David E. Jones</a>
052: * @version $Revision: 1.9 $
053: * @since 2.0
054: */
055: public class ModelService {
056:
057: public static final String module = ModelService.class.getName();
058:
059: public static final String OUT_PARAM = "OUT";
060: public static final String IN_PARAM = "IN";
061:
062: public static final String RESPONSE_MESSAGE = "responseMessage";
063: public static final String RESPOND_SUCCESS = "success";
064: public static final String RESPOND_ERROR = "error";
065: public static final String ERROR_MESSAGE = "errorMessage";
066: public static final String ERROR_MESSAGE_LIST = "errorMessageList";
067: public static final String ERROR_MESSAGE_MAP = "errorMessageMap";
068: public static final String SUCCESS_MESSAGE = "successMessage";
069: public static final String SUCCESS_MESSAGE_LIST = "successMessageList";
070:
071: /** The name of this service */
072: public String name;
073:
074: /** The description of this service */
075: public String description;
076:
077: /** The name of the service engine */
078: public String engineName;
079:
080: /** The namespace of this service */
081: public String nameSpace;
082:
083: /** The package name or location of this service */
084: public String location;
085:
086: /** The method or function to invoke for this service */
087: public String invoke;
088:
089: /** The default Entity to use for auto-attributes */
090: public String defaultEntityName;
091:
092: /** Does this service require authorization */
093: public boolean auth;
094:
095: /** Can this service be exported via RPC, RMI, SOAP, etc */
096: public boolean export;
097:
098: /** Enable verbose debugging when calling this service */
099: public boolean debug;
100:
101: /** Validate the context info for this service */
102: public boolean validate;
103:
104: /** Create a transaction for this service (if one is not already in place...)? */
105: public boolean useTransaction;
106:
107: /** Require a new transaction for this service */
108: public boolean requireNewTransaction;
109:
110: /** Override the default transaction timeout, only works if we start the transaction */
111: public int transactionTimeout;
112:
113: /** Set of services this service implements */
114: public Set implServices = new OrderedSet();
115:
116: /** Set of override parameters */
117: public Set overrideParameters = new OrderedSet();
118:
119: /** List of permission groups for service invocation */
120: public List permissionGroups = new LinkedList();
121:
122: /** Context Information, a list of parameters used by the service, contains ModelParam objects */
123: protected Map contextInfo = new HashMap();
124:
125: /** Context Information, a list of parameters used by the service, contains ModelParam objects */
126: protected List contextParamList = new LinkedList();
127:
128: /** Flag to say if we have pulled in our addition parameters from our implemented service(s) */
129: protected boolean inheritedParameters = false;
130:
131: public ModelService() {
132: }
133:
134: public ModelService(ModelService model) {
135: this .name = model.name;
136: this .description = model.description;
137: this .engineName = model.engineName;
138: this .nameSpace = model.nameSpace;
139: this .location = model.location;
140: this .invoke = model.invoke;
141: this .defaultEntityName = model.defaultEntityName;
142: this .auth = model.auth;
143: this .export = model.export;
144: this .validate = model.validate;
145: this .useTransaction = model.useTransaction || true;
146: this .requireNewTransaction = model.requireNewTransaction || false;
147: this .transactionTimeout = model.transactionTimeout;
148: this .implServices = model.implServices;
149: this .overrideParameters = model.overrideParameters;
150: this .inheritedParameters = model.inheritedParameters();
151:
152: List modelParamList = model.getModelParamList();
153: Iterator i = modelParamList.iterator();
154: while (i.hasNext()) {
155: this .addParamClone((ModelParam) i.next());
156: }
157: }
158:
159: public String toString() {
160: StringBuffer buf = new StringBuffer();
161: buf.append(name + "::");
162: buf.append(description + "::");
163: buf.append(engineName + "::");
164: buf.append(nameSpace + "::");
165: buf.append(location + "::");
166: buf.append(invoke + "::");
167: buf.append(defaultEntityName + "::");
168: buf.append(auth + "::");
169: buf.append(export + "::");
170: buf.append(validate + "::");
171: buf.append(useTransaction + "::");
172: buf.append(requireNewTransaction + "::");
173: buf.append(transactionTimeout + "::");
174: buf.append(implServices + "::");
175: buf.append(overrideParameters + "::");
176: buf.append(contextInfo + "::");
177: buf.append(contextParamList + "::");
178: buf.append(inheritedParameters + "::");
179: return buf.toString();
180: }
181:
182: public String debugInfo() {
183: if (debug || Debug.verboseOn()) {
184: return " [" + this .toString() + "]";
185: }
186: return "";
187: }
188:
189: /**
190: * Test if we have already inherited our interface parameters
191: * @return boolean
192: */
193: public boolean inheritedParameters() {
194: return this .inheritedParameters;
195: }
196:
197: /**
198: * Gets the ModelParam by name
199: * @param name The name of the parameter to get
200: * @return ModelParam object with the specified name
201: */
202: public ModelParam getParam(String name) {
203: return (ModelParam) contextInfo.get(name);
204: }
205:
206: /**
207: * Adds a parameter definition to this service; puts on list in order added
208: * then sorts by order if specified.
209: */
210: public void addParam(ModelParam param) {
211: if (param != null) {
212: contextInfo.put(param.name, param);
213: contextParamList.add(param);
214: }
215: }
216:
217: private void copyParams(Collection params) {
218: if (params != null) {
219: Iterator i = params.iterator();
220: while (i.hasNext()) {
221: ModelParam param = (ModelParam) i.next();
222: addParam(param);
223: }
224: }
225: }
226:
227: /**
228: * Adds a clone of a parameter definition to this service
229: */
230: public void addParamClone(ModelParam param) {
231: if (param != null) {
232: ModelParam newParam = new ModelParam(param);
233: addParam(newParam);
234: }
235: }
236:
237: private void copyParamsAndClone(Collection params) {
238: if (params != null) {
239: Iterator i = params.iterator();
240: while (i.hasNext()) {
241: ModelParam param = (ModelParam) i.next();
242: addParamClone(param);
243: }
244: }
245: }
246:
247: public Set getAllParamNames() {
248: Set nameList = new TreeSet();
249: Iterator i = this .contextParamList.iterator();
250:
251: while (i.hasNext()) {
252: ModelParam p = (ModelParam) i.next();
253: nameList.add(p.name);
254: }
255: return nameList;
256: }
257:
258: public Set getInParamNames() {
259: Set nameList = new TreeSet();
260: Iterator i = this .contextParamList.iterator();
261:
262: while (i.hasNext()) {
263: ModelParam p = (ModelParam) i.next();
264: // don't include OUT parameters in this list, only IN and INOUT
265: if ("OUT".equals(p.mode))
266: continue;
267: nameList.add(p.name);
268: }
269: return nameList;
270: }
271:
272: public Set getOutParamNames() {
273: Set nameList = new TreeSet();
274: Iterator i = this .contextParamList.iterator();
275:
276: while (i.hasNext()) {
277: ModelParam p = (ModelParam) i.next();
278: // don't include IN parameters in this list, only OUT and INOUT
279: if ("IN".equals(p.mode))
280: continue;
281: nameList.add(p.name);
282: }
283: return nameList;
284: }
285:
286: /**
287: * Validates a Map against the IN or OUT parameter information
288: * @param test The Map object to test
289: * @param mode Test either mode IN or mode OUT
290: */
291: public void validate(Map test, String mode)
292: throws ServiceValidationException {
293: Map requiredInfo = new HashMap();
294: Map optionalInfo = new HashMap();
295: boolean verboseOn = Debug.verboseOn();
296:
297: if (verboseOn)
298: Debug.logVerbose("[ModelService.validate] : {" + name
299: + "} : Validating context - " + test, module);
300:
301: // do not validate results with errors
302: if (mode.equals(OUT_PARAM) && test != null
303: && test.containsKey(RESPONSE_MESSAGE)
304: && test.get(RESPONSE_MESSAGE).equals(RESPOND_ERROR)) {
305: if (verboseOn)
306: Debug.logVerbose("[ModelService.validate] : {" + name
307: + "} : response was an error, not validating.",
308: module);
309: return;
310: }
311:
312: // get the info values
313: Collection values = contextInfo.values();
314: Iterator i = values.iterator();
315:
316: while (i.hasNext()) {
317: ModelParam p = (ModelParam) i.next();
318:
319: if (p.mode.equals("INOUT") || p.mode.equals(mode)) {
320: if (!p.optional)
321: requiredInfo.put(p.name, p.type);
322: else
323: optionalInfo.put(p.name, p.type);
324: }
325: }
326:
327: // get the test values
328: Map requiredTest = new HashMap();
329: Map optionalTest = new HashMap();
330:
331: if (test == null)
332: test = new HashMap();
333: requiredTest.putAll(test);
334:
335: List requiredButNull = new ArrayList();
336: if (requiredTest != null) {
337: List keyList = new ArrayList(requiredTest.keySet());
338: Iterator t = keyList.iterator();
339:
340: while (t.hasNext()) {
341: Object key = t.next();
342: Object value = requiredTest.get(key);
343:
344: if (!requiredInfo.containsKey(key)) {
345: requiredTest.remove(key);
346: optionalTest.put(key, value);
347: } else if (value == null) {
348: requiredButNull.add(key);
349: }
350: }
351: }
352:
353: // check for requiredButNull fields and return an error since null values are not allowed for required fields
354: if (requiredButNull.size() > 0) {
355: String missing = "";
356: Iterator rbni = requiredButNull.iterator();
357: while (rbni.hasNext()) {
358: String missingKey = (String) rbni.next();
359: missing = missing + missingKey;
360: if (rbni.hasNext()) {
361: missing = missing + ", ";
362: }
363: }
364: throw new ServiceValidationException(
365: "The following required parameters are missing: "
366: + missing, this , requiredButNull, null,
367: mode);
368: }
369:
370: if (verboseOn) {
371: String requiredNames = "";
372: Iterator requiredIter = requiredInfo.keySet().iterator();
373: while (requiredIter.hasNext()) {
374: requiredNames = requiredNames + requiredIter.next();
375: if (requiredIter.hasNext()) {
376: requiredNames = requiredNames + ", ";
377: }
378: }
379: Debug.logVerbose(
380: "[ModelService.validate] : required fields - "
381: + requiredNames, module);
382:
383: Debug.logVerbose(
384: "[ModelService.validate] : {" + name + "} : ("
385: + mode + ") Required - "
386: + requiredTest.size() + " / "
387: + requiredInfo.size(), module);
388: Debug.logVerbose(
389: "[ModelService.validate] : {" + name + "} : ("
390: + mode + ") Optional - "
391: + optionalTest.size() + " / "
392: + optionalInfo.size(), module);
393: }
394:
395: try {
396: validate(requiredInfo, requiredTest, true, this , mode);
397: validate(optionalInfo, optionalTest, false, this , mode);
398: } catch (ServiceValidationException e) {
399: Debug.logError("[ModelService.validate] : {" + name
400: + "} : (" + mode + ") Required test error: "
401: + e.toString(), module);
402: throw e;
403: }
404: }
405:
406: /**
407: * Validates a map of name, object types to a map of name, objects
408: * @param info The map of name, object types
409: * @param test The map to test its value types.
410: * @param reverse Test the maps in reverse.
411: */
412: public static void validate(Map info, Map test, boolean reverse,
413: ModelService model, String mode)
414: throws ServiceValidationException {
415: if (info == null || test == null) {
416: throw new ServiceValidationException(
417: "Cannot validate NULL maps");
418: }
419:
420: String serviceNameMessage = "";
421: if (model != null && model.name != null) {
422: serviceNameMessage = "For service [" + model.name + "] ";
423: }
424:
425: // * Validate keys first
426: Set testSet = test.keySet();
427: Set keySet = info.keySet();
428:
429: // Quick check for sizes
430: if (info.size() == 0 && test.size() == 0)
431: return;
432: // This is to see if the test set contains all from the info set (reverse)
433: if (reverse && !testSet.containsAll(keySet)) {
434: Set missing = new TreeSet(keySet);
435:
436: missing.removeAll(testSet);
437: String missingStr = "";
438: Iterator iter = missing.iterator();
439:
440: while (iter.hasNext()) {
441: missingStr += (String) iter.next();
442: if (iter.hasNext()) {
443: missingStr += ", ";
444: }
445: }
446:
447: throw new ServiceValidationException(serviceNameMessage
448: + "the following required parameters are missing: "
449: + missingStr, model, new ArrayList(missing), null,
450: mode);
451: }
452: // This is to see if the info set contains all from the test set
453: if (!keySet.containsAll(testSet)) {
454: Set extra = new TreeSet(testSet);
455:
456: extra.removeAll(keySet);
457: String extraStr = "";
458: Iterator iter = extra.iterator();
459:
460: while (iter.hasNext()) {
461: extraStr += (String) iter.next();
462: if (iter.hasNext()) {
463: extraStr += ", ";
464: }
465: }
466: throw new ServiceValidationException(serviceNameMessage
467: + "unknown parameters found: " + extraStr, model,
468: null, new ArrayList(extra), mode);
469: }
470:
471: // * Validate types next
472: Iterator i = testSet.iterator();
473:
474: while (i.hasNext()) {
475: Object key = i.next();
476: Object testObject = test.get(key);
477: String infoType = (String) info.get(key);
478:
479: if (!ObjectType.instanceOf(testObject, infoType, null)) {
480: String testType = testObject == null ? "null"
481: : testObject.getClass().getName();
482: throw new ServiceValidationException(serviceNameMessage
483: + "type check failed for field [" + key
484: + "]; expected type is [" + infoType
485: + "]; actual type is [" + testType + "]");
486: }
487: }
488: }
489:
490: /**
491: * Gets the parameter names of the specified mode (IN/OUT/INOUT). The
492: * parameters will be returned in the order specified in the file.
493: * Note: IN and OUT will also contains INOUT parameters.
494: * @param mode The mode (IN/OUT/INOUT)
495: * @param optional True if to include optional parameters
496: * @return List of parameter names
497: */
498: public List getParameterNames(String mode, boolean optional) {
499: List names = new ArrayList();
500:
501: if (!"IN".equals(mode) && !"OUT".equals(mode)
502: && !"INOUT".equals(mode)) {
503: return names;
504: }
505: if (contextInfo.size() == 0) {
506: return names;
507: }
508: Iterator i = contextParamList.iterator();
509:
510: while (i.hasNext()) {
511: ModelParam param = (ModelParam) i.next();
512:
513: if (param.mode.equals("INOUT") || param.mode.equals(mode)) {
514: if (optional || (!optional && !param.optional)) {
515: names.add(param.name);
516: }
517: }
518: }
519: return names;
520: }
521:
522: /**
523: * Creates a new Map based from an existing map with just valid parameters.
524: * Tries to convert parameters to required type.
525: * @param source The source map
526: * @param mode The mode which to build the new map
527: */
528: public Map makeValid(Map source, String mode) {
529: return makeValid(source, mode, true);
530: }
531:
532: /**
533: * Creates a new Map based from an existing map with just valid parameters.
534: * Tries to convert parameters to required type.
535: * @param source The source map
536: * @param mode The mode which to build the new map
537: * @param includeInternal When false will exclude internal fields
538: */
539: public Map makeValid(Map source, String mode,
540: boolean includeInternal) {
541: Map target = new HashMap();
542:
543: if (source == null) {
544: return target;
545: }
546: if (!"IN".equals(mode) && !"OUT".equals(mode)
547: && !"INOUT".equals(mode)) {
548: return target;
549: }
550: if (contextInfo.size() == 0) {
551: return target;
552: }
553: Iterator i = contextParamList.iterator();
554:
555: while (i.hasNext()) {
556: ModelParam param = (ModelParam) i.next();
557: boolean internalParam = param.internal;
558:
559: if (param.mode.equals("INOUT") || param.mode.equals(mode)) {
560: Object key = param.name;
561:
562: // internal map of strings
563: if (param.stringMapPrefix != null
564: && param.stringMapPrefix.length() > 0
565: && !source.containsKey(key)) {
566: Map paramMap = this .makePrefixMap(source, param);
567: if (paramMap != null && paramMap.size() > 0) {
568: target.put(key, paramMap);
569: }
570: // internal list of strings
571: } else if (param.stringListSuffix != null
572: && param.stringListSuffix.length() > 0
573: && !source.containsKey(key)) {
574: List paramList = this .makeSuffixList(source, param);
575: if (paramList != null && paramList.size() > 0) {
576: target.put(key, paramList);
577: }
578: // other attributes
579: } else {
580: if (source.containsKey(key)) {
581: if ((param.internal && includeInternal)
582: || (!param.internal)) {
583: Object value = source.get(key);
584:
585: try {
586: value = ObjectType.simpleTypeConvert(
587: value, param.type, null, null);
588: } catch (GeneralException e) {
589: Debug.logWarning(
590: "[ModelService.makeValid] : Simple type conversion of param "
591: + key + " failed: "
592: + e.toString(), module);
593: }
594: target.put(key, value);
595: }
596: }
597: }
598: }
599: }
600: return target;
601: }
602:
603: private Map makePrefixMap(Map source, ModelParam param) {
604: Map paramMap = new HashMap();
605: Set sourceSet = source.keySet();
606: Iterator i = sourceSet.iterator();
607: while (i.hasNext()) {
608: String key = (String) i.next();
609: if (key.startsWith(param.stringMapPrefix)) {
610: paramMap.put(key, source.get(key));
611: }
612: }
613: return paramMap;
614: }
615:
616: private List makeSuffixList(Map source, ModelParam param) {
617: List paramList = new ArrayList();
618: Set sourceSet = source.keySet();
619: Iterator i = sourceSet.iterator();
620: while (i.hasNext()) {
621: String key = (String) i.next();
622: if (key.endsWith(param.stringListSuffix)) {
623: paramList.add(source.get(key));
624: }
625: }
626: return paramList;
627: }
628:
629: public boolean containsPermissions() {
630: if (this .permissionGroups != null
631: && this .permissionGroups.size() > 0) {
632: return true;
633: }
634: return false;
635: }
636:
637: /**
638: * Evaluates permissions for a service.
639: * @param security The security object to use for permission checking
640: * @param userLogin The logged in user's value object
641: * @return true if all permissions evaluate true.
642: */
643: public boolean evalPermissions(Security security,
644: GenericValue userLogin) {
645: if (this .containsPermissions()) {
646: Iterator i = this .permissionGroups.iterator();
647: while (i.hasNext()) {
648: ModelPermGroup group = (ModelPermGroup) i.next();
649: if (!group.evalPermissions(security, userLogin)) {
650: return false;
651: }
652: }
653: return true;
654: } else {
655: return true;
656: }
657: }
658:
659: /**
660: * Gets a list of required IN parameters in sequence.
661: * @return A list of required IN parameters in the order which they were defined.
662: */
663: public List getInParameterSequence(Map source) {
664: List target = new LinkedList();
665:
666: if (source == null) {
667: return target;
668: }
669: if (contextInfo == null || contextInfo.size() == 0) {
670: return target;
671: }
672: Iterator i = this .contextParamList.iterator();
673:
674: while (i.hasNext()) {
675: ModelParam p = (ModelParam) i.next();
676:
677: // don't include OUT parameters in this list, only IN and INOUT
678: if ("OUT".equals(p.mode))
679: continue;
680:
681: Object srcObject = source.get(p.name);
682:
683: if (srcObject != null) {
684: target.add(srcObject);
685: }
686: }
687: return target;
688: }
689:
690: /**
691: * Returns a list of ModelParam objects in the order they were defined when
692: * the service was created.
693: */
694: public List getModelParamList() {
695: return new LinkedList(this .contextParamList);
696: }
697:
698: /**
699: * Returns a list of ModelParam objects in the order they were defined when
700: * the service was created.
701: */
702: public List getInModelParamList() {
703: List inList = new LinkedList();
704: Iterator i = this .contextParamList.iterator();
705:
706: while (i.hasNext()) {
707: ModelParam p = (ModelParam) i.next();
708:
709: // don't include OUT parameters in this list, only IN and INOUT
710: if ("OUT".equals(p.mode))
711: continue;
712: inList.add(p);
713: }
714: return inList;
715: }
716:
717: /**
718: * Run the interface update and inherit all interface parameters
719: * @param dctx The DispatchContext to use for service lookups
720: */
721: public synchronized void interfaceUpdate(DispatchContext dctx)
722: throws GenericServiceException {
723: if (!inheritedParameters) {
724: // services w/ engine 'group' auto-implement the grouped services
725: if (this .engineName.equals("group")
726: && implServices.size() == 0) {
727: GroupModel group = ServiceGroupReader
728: .getGroupModel(this .location);
729: if (group != null) {
730: List groupedServices = group.getServices();
731: Iterator i = groupedServices.iterator();
732: while (i.hasNext()) {
733: GroupServiceModel sm = (GroupServiceModel) i
734: .next();
735: implServices.add(sm.getName());
736: if (Debug.verboseOn())
737: Debug.logVerbose("Adding service ["
738: + sm.getName()
739: + "] as interface of: ["
740: + this .name + "]", module);
741: }
742: }
743: }
744:
745: // handle interfaces
746: if (implServices != null && implServices.size() > 0
747: && dctx != null) {
748: // backup the old info
749: List oldParams = this .contextParamList;
750:
751: // reset the fields
752: this .contextInfo = new HashMap();
753: this .contextParamList = new LinkedList();
754:
755: Iterator implIter = implServices.iterator();
756: while (implIter.hasNext()) {
757: String serviceName = (String) implIter.next();
758: ModelService model = dctx
759: .getModelService(serviceName);
760: if (model != null) {
761: copyParamsAndClone(model.contextInfo.values());
762: } else {
763: Debug.logWarning("Inherited model ["
764: + serviceName + "] not found for ["
765: + this .name + "]", module);
766: }
767: }
768:
769: // put the old values back on top
770: copyParams(oldParams);
771: }
772:
773: // handle any override parameters
774: if (overrideParameters != null
775: && overrideParameters.size() > 0) {
776: Iterator keySetIter = overrideParameters.iterator();
777: while (keySetIter.hasNext()) {
778: ModelParam overrideParam = (ModelParam) keySetIter
779: .next();
780: ModelParam existingParam = (ModelParam) contextInfo
781: .get(overrideParam.name);
782:
783: // keep the list clean, remove it then add it back
784: contextParamList.remove(existingParam);
785:
786: if (existingParam != null) {
787: // now re-write the parameters
788: if (overrideParam.type != null
789: && overrideParam.type.length() > 0) {
790: existingParam.type = overrideParam.type;
791: }
792: if (overrideParam.mode != null
793: && overrideParam.mode.length() > 0) {
794: existingParam.mode = overrideParam.mode;
795: }
796: if (overrideParam.entityName != null
797: && overrideParam.entityName.length() > 0) {
798: existingParam.entityName = overrideParam.entityName;
799: }
800: if (overrideParam.fieldName != null
801: && overrideParam.fieldName.length() > 0) {
802: existingParam.fieldName = overrideParam.fieldName;
803: }
804: if (overrideParam.formLabel != null
805: && overrideParam.formLabel.length() > 0) {
806: existingParam.formLabel = overrideParam.formLabel;
807: }
808: if (overrideParam.overrideFormDisplay) {
809: existingParam.formDisplay = overrideParam.formDisplay;
810: }
811: if (overrideParam.overrideOptional) {
812: existingParam.optional = overrideParam.optional;
813: }
814: addParam(existingParam);
815: } else {
816: Debug.logWarning(
817: "Override param found but no parameter existing; ignoring: "
818: + overrideParam.name, module);
819: }
820: }
821: }
822:
823: // set the flag so we don't do this again
824: this .inheritedParameters = true;
825: }
826: }
827: }
|