001: /*******************************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *******************************************************************************/package org.ofbiz.widget.screen;
019:
020: import java.io.Serializable;
021: import java.lang.reflect.Method;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025:
026: import javolution.util.FastList;
027:
028: import org.ofbiz.base.util.*;
029: import org.ofbiz.base.util.collections.FlexibleMapAccessor;
030: import org.ofbiz.base.util.string.FlexibleStringExpander;
031: import org.ofbiz.entity.GenericValue;
032: import org.ofbiz.entityext.permission.EntityPermissionChecker;
033: import org.ofbiz.minilang.operation.BaseCompare;
034: import org.ofbiz.security.Security;
035: import org.ofbiz.service.*;
036:
037: import org.apache.oro.text.regex.MalformedPatternException;
038: import org.apache.oro.text.regex.Pattern;
039: import org.apache.oro.text.regex.PatternCompiler;
040: import org.apache.oro.text.regex.PatternMatcher;
041: import org.apache.oro.text.regex.Perl5Compiler;
042: import org.apache.oro.text.regex.Perl5Matcher;
043: import org.w3c.dom.Element;
044:
045: /**
046: * Widget Library - Screen model condition class
047: */
048: public class ModelScreenCondition implements Serializable {
049: public static final String module = ModelScreenCondition.class
050: .getName();
051:
052: protected ModelScreen modelScreen;
053: protected ScreenCondition rootCondition;
054:
055: public ModelScreenCondition(ModelScreen modelScreen,
056: Element conditionElement) {
057: this .modelScreen = modelScreen;
058: Element firstChildElement = UtilXml
059: .firstChildElement(conditionElement);
060: this .rootCondition = readCondition(modelScreen,
061: firstChildElement);
062: }
063:
064: public boolean eval(Map context) {
065: if (rootCondition == null) {
066: return true;
067: }
068: return rootCondition.eval(context);
069: }
070:
071: public static abstract class ScreenCondition implements
072: Serializable {
073: protected ModelScreen modelScreen;
074:
075: public ScreenCondition(ModelScreen modelScreen,
076: Element conditionElement) {
077: this .modelScreen = modelScreen;
078: }
079:
080: public abstract boolean eval(Map context);
081: }
082:
083: public static List readSubConditions(ModelScreen modelScreen,
084: Element conditionElement) {
085: List condList = FastList.newInstance();
086: List subElementList = UtilXml
087: .childElementList(conditionElement);
088: Iterator subElementIter = subElementList.iterator();
089: while (subElementIter.hasNext()) {
090: Element subElement = (Element) subElementIter.next();
091: condList.add(readCondition(modelScreen, subElement));
092: }
093: return condList;
094: }
095:
096: public static ScreenCondition readCondition(
097: ModelScreen modelScreen, Element conditionElement) {
098: if (conditionElement == null) {
099: return null;
100: }
101: if ("and".equals(conditionElement.getNodeName())) {
102: return new And(modelScreen, conditionElement);
103: } else if ("xor".equals(conditionElement.getNodeName())) {
104: return new Xor(modelScreen, conditionElement);
105: } else if ("or".equals(conditionElement.getNodeName())) {
106: return new Or(modelScreen, conditionElement);
107: } else if ("not".equals(conditionElement.getNodeName())) {
108: return new Not(modelScreen, conditionElement);
109: } else if ("if-service-permission".equals(conditionElement
110: .getNodeName())) {
111: return new IfServicePermission(modelScreen,
112: conditionElement);
113: } else if ("if-has-permission".equals(conditionElement
114: .getNodeName())) {
115: return new IfHasPermission(modelScreen, conditionElement);
116: } else if ("if-validate-method".equals(conditionElement
117: .getNodeName())) {
118: return new IfValidateMethod(modelScreen, conditionElement);
119: } else if ("if-compare".equals(conditionElement.getNodeName())) {
120: return new IfCompare(modelScreen, conditionElement);
121: } else if ("if-compare-field".equals(conditionElement
122: .getNodeName())) {
123: return new IfCompareField(modelScreen, conditionElement);
124: } else if ("if-regexp".equals(conditionElement.getNodeName())) {
125: return new IfRegexp(modelScreen, conditionElement);
126: } else if ("if-empty".equals(conditionElement.getNodeName())) {
127: return new IfEmpty(modelScreen, conditionElement);
128: } else if ("if-entity-permission".equals(conditionElement
129: .getNodeName())) {
130: return new IfEntityPermission(modelScreen, conditionElement);
131: } else {
132: throw new IllegalArgumentException(
133: "Condition element not supported with name: "
134: + conditionElement.getNodeName());
135: }
136: }
137:
138: public static class And extends ScreenCondition {
139: protected List subConditions;
140:
141: public And(ModelScreen modelScreen, Element condElement) {
142: super (modelScreen, condElement);
143: this .subConditions = readSubConditions(modelScreen,
144: condElement);
145: }
146:
147: public boolean eval(Map context) {
148: // return false for the first one in the list that is false, basic and algo
149: Iterator subConditionIter = this .subConditions.iterator();
150: while (subConditionIter.hasNext()) {
151: ScreenCondition subCondition = (ScreenCondition) subConditionIter
152: .next();
153: if (!subCondition.eval(context)) {
154: return false;
155: }
156: }
157: return true;
158: }
159: }
160:
161: public static class Xor extends ScreenCondition {
162: protected List subConditions;
163:
164: public Xor(ModelScreen modelScreen, Element condElement) {
165: super (modelScreen, condElement);
166: this .subConditions = readSubConditions(modelScreen,
167: condElement);
168: }
169:
170: public boolean eval(Map context) {
171: // if more than one is true stop immediately and return false; if all are false return false; if only one is true return true
172: boolean foundOneTrue = false;
173: Iterator subConditionIter = this .subConditions.iterator();
174: while (subConditionIter.hasNext()) {
175: ScreenCondition subCondition = (ScreenCondition) subConditionIter
176: .next();
177: if (subCondition.eval(context)) {
178: if (foundOneTrue) {
179: // now found two true, so return false
180: return false;
181: } else {
182: foundOneTrue = true;
183: }
184: }
185: }
186: return foundOneTrue;
187: }
188: }
189:
190: public static class Or extends ScreenCondition {
191: protected List subConditions;
192:
193: public Or(ModelScreen modelScreen, Element condElement) {
194: super (modelScreen, condElement);
195: this .subConditions = readSubConditions(modelScreen,
196: condElement);
197: }
198:
199: public boolean eval(Map context) {
200: // return true for the first one in the list that is true, basic or algo
201: Iterator subConditionIter = this .subConditions.iterator();
202: while (subConditionIter.hasNext()) {
203: ScreenCondition subCondition = (ScreenCondition) subConditionIter
204: .next();
205: if (subCondition.eval(context)) {
206: return true;
207: }
208: }
209: return false;
210: }
211: }
212:
213: public static class Not extends ScreenCondition {
214: protected ScreenCondition subCondition;
215:
216: public Not(ModelScreen modelScreen, Element condElement) {
217: super (modelScreen, condElement);
218: Element firstChildElement = UtilXml
219: .firstChildElement(condElement);
220: this .subCondition = readCondition(modelScreen,
221: firstChildElement);
222: }
223:
224: public boolean eval(Map context) {
225: return !this .subCondition.eval(context);
226: }
227: }
228:
229: public static class IfServicePermission extends ScreenCondition {
230: protected FlexibleStringExpander serviceExdr;
231: protected FlexibleStringExpander actionExdr;
232: protected FlexibleStringExpander ctxMapExdr;
233: protected FlexibleStringExpander resExdr;
234:
235: public IfServicePermission(ModelScreen modelScreen,
236: Element condElement) {
237: super (modelScreen, condElement);
238: this .serviceExdr = new FlexibleStringExpander(condElement
239: .getAttribute("service-name"));
240: this .actionExdr = new FlexibleStringExpander(condElement
241: .getAttribute("main-action"));
242: this .ctxMapExdr = new FlexibleStringExpander(condElement
243: .getAttribute("context-map"));
244: this .resExdr = new FlexibleStringExpander(condElement
245: .getAttribute("resource-description"));
246: }
247:
248: public boolean eval(Map context) {
249: // if no user is logged in, treat as if the user does not have permission
250: GenericValue userLogin = (GenericValue) context
251: .get("userLogin");
252: if (userLogin != null) {
253: String serviceName = serviceExdr.expandString(context);
254: String mainAction = actionExdr.expandString(context);
255: String contextMap = ctxMapExdr.expandString(context);
256: String resource = resExdr.expandString(context);
257: if (UtilValidate.isEmpty(resource)) {
258: resource = serviceName;
259: }
260:
261: if (UtilValidate.isEmpty(serviceName)) {
262: Debug.logWarning(
263: "No permission service-name specified!",
264: module);
265: return false;
266: }
267:
268: Map serviceContext;
269: Object internalSvcMap = context.get(contextMap);
270: if (internalSvcMap != null
271: && (internalSvcMap instanceof Map)) {
272: serviceContext = (Map) internalSvcMap;
273:
274: // copy the required internal fields
275: serviceContext.put("userLogin", context
276: .get("userLogin"));
277: serviceContext.put("locale", context.get("locale"));
278: } else {
279: serviceContext = context;
280: }
281:
282: // get the service objects
283: LocalDispatcher dispatcher = this .modelScreen
284: .getDispatcher(context);
285: DispatchContext dctx = dispatcher.getDispatchContext();
286:
287: // get the service
288: ModelService permService;
289: try {
290: permService = dctx.getModelService(serviceName);
291: } catch (GenericServiceException e) {
292: Debug.logError(e, module);
293: return false;
294: }
295:
296: if (permService != null) {
297: // build the context
298: Map svcCtx = permService.makeValid(serviceContext,
299: ModelService.IN_PARAM);
300: svcCtx.put("resourceDescription", resource);
301: if (UtilValidate.isNotEmpty(mainAction)) {
302: svcCtx.put("mainAction", mainAction);
303: }
304:
305: // invoke the service
306: Map resp;
307: try {
308: resp = dispatcher.runSync(permService.name,
309: svcCtx, 300, true);
310: } catch (GenericServiceException e) {
311: Debug.logError(e, module);
312: return false;
313: }
314: if (ServiceUtil.isError(resp)
315: || ServiceUtil.isFailure(resp)) {
316: Debug.logError(ServiceUtil
317: .getErrorMessage(resp), module);
318: return false;
319: }
320: Boolean hasPermission = (Boolean) resp
321: .get("hasPermission");
322: if (hasPermission != null) {
323: return hasPermission.booleanValue();
324: }
325: }
326: }
327: return false;
328: }
329: }
330:
331: public static class IfHasPermission extends ScreenCondition {
332: protected FlexibleStringExpander permissionExdr;
333: protected FlexibleStringExpander actionExdr;
334:
335: public IfHasPermission(ModelScreen modelScreen,
336: Element condElement) {
337: super (modelScreen, condElement);
338: this .permissionExdr = new FlexibleStringExpander(
339: condElement.getAttribute("permission"));
340: this .actionExdr = new FlexibleStringExpander(condElement
341: .getAttribute("action"));
342: }
343:
344: public boolean eval(Map context) {
345: // if no user is logged in, treat as if the user does not have permission
346: GenericValue userLogin = (GenericValue) context
347: .get("userLogin");
348: if (userLogin != null) {
349: String permission = permissionExdr
350: .expandString(context);
351: String action = actionExdr.expandString(context);
352:
353: Security security = (Security) context.get("security");
354: if (action != null && action.length() > 0) {
355: // run hasEntityPermission
356: if (security.hasEntityPermission(permission,
357: action, userLogin)) {
358: return true;
359: }
360: } else {
361: // run hasPermission
362: if (security.hasPermission(permission, userLogin)) {
363: return true;
364: }
365: }
366: }
367: return false;
368: }
369: }
370:
371: public static class IfValidateMethod extends ScreenCondition {
372: protected FlexibleMapAccessor fieldAcsr;
373: protected FlexibleStringExpander methodExdr;
374: protected FlexibleStringExpander classExdr;
375:
376: public IfValidateMethod(ModelScreen modelScreen,
377: Element condElement) {
378: super (modelScreen, condElement);
379: this .fieldAcsr = new FlexibleMapAccessor(condElement
380: .getAttribute("field-name"));
381: this .methodExdr = new FlexibleStringExpander(condElement
382: .getAttribute("method"));
383: this .classExdr = new FlexibleStringExpander(condElement
384: .getAttribute("class"));
385: }
386:
387: public boolean eval(Map context) {
388: String methodName = this .methodExdr.expandString(context);
389: String className = this .classExdr.expandString(context);
390:
391: Object fieldVal = this .fieldAcsr.get(context);
392: String fieldString = null;
393: if (fieldVal != null) {
394: try {
395: fieldString = (String) ObjectType
396: .simpleTypeConvert(fieldVal, "String",
397: null, null);
398: } catch (GeneralException e) {
399: Debug
400: .logError(
401: e,
402: "Could not convert object to String, using empty String",
403: module);
404: }
405: }
406:
407: // always use an empty string by default
408: if (fieldString == null)
409: fieldString = "";
410:
411: Class[] paramTypes = new Class[] { String.class };
412: Object[] params = new Object[] { fieldString };
413:
414: Class valClass;
415: try {
416: valClass = ObjectType.loadClass(className);
417: } catch (ClassNotFoundException cnfe) {
418: Debug.logError("Could not find validation class: "
419: + className, module);
420: return false;
421: }
422:
423: Method valMethod;
424: try {
425: valMethod = valClass.getMethod(methodName, paramTypes);
426: } catch (NoSuchMethodException cnfe) {
427: Debug
428: .logError(
429: "Could not find validation method: "
430: + methodName + " of class "
431: + className, module);
432: return false;
433: }
434:
435: Boolean resultBool = Boolean.FALSE;
436: try {
437: resultBool = (Boolean) valMethod.invoke(null, params);
438: } catch (Exception e) {
439: Debug.logError(e, "Error in IfValidationMethod "
440: + methodName + " of class " + className
441: + ", defaulting to false ", module);
442: }
443:
444: return resultBool.booleanValue();
445: }
446: }
447:
448: public static class IfCompare extends ScreenCondition {
449: protected FlexibleMapAccessor fieldAcsr;
450: protected FlexibleStringExpander valueExdr;
451:
452: protected String operator;
453: protected String type;
454: protected FlexibleStringExpander formatExdr;
455:
456: public IfCompare(ModelScreen modelScreen, Element condElement) {
457: super (modelScreen, condElement);
458: this .fieldAcsr = new FlexibleMapAccessor(condElement
459: .getAttribute("field-name"));
460: this .valueExdr = new FlexibleStringExpander(condElement
461: .getAttribute("value"));
462:
463: this .operator = condElement.getAttribute("operator");
464: this .type = condElement.getAttribute("type");
465:
466: this .formatExdr = new FlexibleStringExpander(condElement
467: .getAttribute("format"));
468: }
469:
470: public boolean eval(Map context) {
471: String value = this .valueExdr.expandString(context);
472: String format = this .formatExdr.expandString(context);
473:
474: Object fieldVal = this .fieldAcsr.get(context);
475:
476: // always use an empty string by default
477: if (fieldVal == null) {
478: fieldVal = "";
479: }
480:
481: List messages = FastList.newInstance();
482: Boolean resultBool = BaseCompare.doRealCompare(fieldVal,
483: value, operator, type, format, messages, null,
484: null, true);
485: if (messages.size() > 0) {
486: messages.add(0,
487: "Error with comparison in if-compare between field ["
488: + fieldAcsr.toString()
489: + "] with value [" + fieldVal
490: + "] and value [" + value
491: + "] with operator [" + operator
492: + "] and type [" + type + "]: ");
493:
494: StringBuffer fullString = new StringBuffer();
495: Iterator miter = messages.iterator();
496: while (miter.hasNext()) {
497: fullString.append((String) miter.next());
498: }
499: Debug.logWarning(fullString.toString(), module);
500:
501: throw new IllegalArgumentException(fullString
502: .toString());
503: }
504:
505: return resultBool.booleanValue();
506: }
507: }
508:
509: public static class IfCompareField extends ScreenCondition {
510: protected FlexibleMapAccessor fieldAcsr;
511: protected FlexibleMapAccessor toFieldAcsr;
512:
513: protected String operator;
514: protected String type;
515: protected FlexibleStringExpander formatExdr;
516:
517: public IfCompareField(ModelScreen modelScreen,
518: Element condElement) {
519: super (modelScreen, condElement);
520: this .fieldAcsr = new FlexibleMapAccessor(condElement
521: .getAttribute("field-name"));
522: this .toFieldAcsr = new FlexibleMapAccessor(condElement
523: .getAttribute("to-field-name"));
524:
525: this .operator = condElement.getAttribute("operator");
526: this .type = condElement.getAttribute("type");
527:
528: this .formatExdr = new FlexibleStringExpander(condElement
529: .getAttribute("format"));
530: }
531:
532: public boolean eval(Map context) {
533: String format = this .formatExdr.expandString(context);
534:
535: Object fieldVal = this .fieldAcsr.get(context);
536: Object toFieldVal = this .toFieldAcsr.get(context);
537:
538: // always use an empty string by default
539: if (fieldVal == null) {
540: fieldVal = "";
541: }
542:
543: List messages = FastList.newInstance();
544: Boolean resultBool = BaseCompare.doRealCompare(fieldVal,
545: toFieldVal, operator, type, format, messages, null,
546: null, false);
547: if (messages.size() > 0) {
548: messages.add(0,
549: "Error with comparison in if-compare-field between field ["
550: + fieldAcsr.toString()
551: + "] with value [" + fieldVal
552: + "] and to-field ["
553: + toFieldAcsr.toString()
554: + "] with value [" + toFieldVal
555: + "] with operator [" + operator
556: + "] and type [" + type + "]: ");
557:
558: StringBuffer fullString = new StringBuffer();
559: Iterator miter = messages.iterator();
560: while (miter.hasNext()) {
561: fullString.append((String) miter.next());
562: }
563: Debug.logWarning(fullString.toString(), module);
564:
565: throw new IllegalArgumentException(fullString
566: .toString());
567: }
568:
569: return resultBool.booleanValue();
570: }
571: }
572:
573: public static class IfRegexp extends ScreenCondition {
574: static PatternMatcher matcher = new Perl5Matcher();
575: static PatternCompiler compiler = new Perl5Compiler();
576:
577: protected FlexibleMapAccessor fieldAcsr;
578: protected FlexibleStringExpander exprExdr;
579:
580: public IfRegexp(ModelScreen modelScreen, Element condElement) {
581: super (modelScreen, condElement);
582: this .fieldAcsr = new FlexibleMapAccessor(condElement
583: .getAttribute("field-name"));
584: this .exprExdr = new FlexibleStringExpander(condElement
585: .getAttribute("expr"));
586: }
587:
588: public boolean eval(Map context) {
589: Object fieldVal = this .fieldAcsr.get(context);
590: String expr = this .exprExdr.expandString(context);
591: Pattern pattern;
592: try {
593: pattern = compiler.compile(expr);
594: } catch (MalformedPatternException e) {
595: String errMsg = "Error in evaluation in if-regexp in screen: "
596: + e.toString();
597: Debug.logError(e, errMsg, module);
598: throw new IllegalArgumentException(errMsg);
599: }
600:
601: String fieldString = null;
602: try {
603: fieldString = (String) ObjectType.simpleTypeConvert(
604: fieldVal, "String", null, null);
605: } catch (GeneralException e) {
606: Debug
607: .logError(
608: e,
609: "Could not convert object to String, using empty String",
610: module);
611: }
612: // always use an empty string by default
613: if (fieldString == null)
614: fieldString = "";
615:
616: return matcher.matches(fieldString, pattern);
617: }
618: }
619:
620: public static class IfEmpty extends ScreenCondition {
621: protected FlexibleMapAccessor fieldAcsr;
622:
623: public IfEmpty(ModelScreen modelScreen, Element condElement) {
624: super (modelScreen, condElement);
625: this .fieldAcsr = new FlexibleMapAccessor(condElement
626: .getAttribute("field-name"));
627: }
628:
629: public boolean eval(Map context) {
630: Object fieldVal = this .fieldAcsr.get(context);
631: return ObjectType.isEmpty(fieldVal);
632: }
633: }
634:
635: public static class IfEntityPermission extends ScreenCondition {
636: protected EntityPermissionChecker permissionChecker;
637:
638: public IfEntityPermission(ModelScreen modelScreen,
639: Element condElement) {
640: super (modelScreen, condElement);
641: this .permissionChecker = new EntityPermissionChecker(
642: condElement);
643: }
644:
645: public boolean eval(Map context) {
646: return permissionChecker.runPermissionCheck(context);
647: }
648: }
649: }
|