Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/AbstractModelAction.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/AbstractModelAction.java?rev=1652638&view=auto ============================================================================== --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/AbstractModelAction.java (added) +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/AbstractModelAction.java Sat Jan 17 16:47:23 2015 @@ -0,0 +1,951 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.ofbiz.widget; + +import java.io.Serializable; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; +import java.util.regex.PatternSyntaxException; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpSession; + +import org.ofbiz.base.util.Debug; +import org.ofbiz.base.util.GeneralException; +import org.ofbiz.base.util.ObjectType; +import org.ofbiz.base.util.ScriptUtil; +import org.ofbiz.base.util.StringUtil; +import org.ofbiz.base.util.UtilGenerics; +import org.ofbiz.base.util.UtilProperties; +import org.ofbiz.base.util.UtilValidate; +import org.ofbiz.base.util.UtilXml; +import org.ofbiz.base.util.collections.FlexibleMapAccessor; +import org.ofbiz.base.util.collections.ResourceBundleMapWrapper; +import org.ofbiz.base.util.string.FlexibleStringExpander; +import org.ofbiz.entity.GenericEntityException; +import org.ofbiz.entity.GenericValue; +import org.ofbiz.entity.finder.ByAndFinder; +import org.ofbiz.entity.finder.ByConditionFinder; +import org.ofbiz.entity.finder.EntityFinderUtil; +import org.ofbiz.entity.finder.PrimaryKeyFinder; +import org.ofbiz.entity.util.EntityUtilProperties; +import org.ofbiz.minilang.MiniLangException; +import org.ofbiz.minilang.SimpleMethod; +import org.ofbiz.minilang.method.MethodContext; +import org.ofbiz.service.DispatchContext; +import org.ofbiz.service.GenericServiceException; +import org.ofbiz.service.ModelService; +import org.ofbiz.widget.xml.XmlWidgetActionVisitor; +import org.w3c.dom.Element; + +/** + * Abstract base class for the action models. + */ +@SuppressWarnings("serial") +public abstract class AbstractModelAction implements Serializable, ModelAction { + + /* + * ----------------------------------------------------------------------- * + * DEVELOPERS PLEASE READ + * ----------------------------------------------------------------------- * + * + * This model is intended to be a read-only data structure that represents + * an XML element. Outside of object construction, the class should not + * have any behaviors. + * + * Instances of this class will be shared by multiple threads - therefore + * it is immutable. DO NOT CHANGE THE OBJECT'S STATE AT RUN TIME! + * + */ + + public static final String module = AbstractModelAction.class.getName(); + + /** + * Returns a new <code>ModelAction</code> instance, built from <code>actionElement</code>. + * + * @param modelWidget The <code>ModelWidget</code> that contains the <actions> element + * @param actionElement + * @return A new <code>ModelAction</code> instance + */ + public static ModelAction newInstance(ModelWidget modelWidget, Element actionElement) { + if ("set".equals(actionElement.getNodeName())) { + return new SetField(modelWidget, actionElement); + } else if ("property-map".equals(actionElement.getNodeName())) { + return new PropertyMap(modelWidget, actionElement); + } else if ("property-to-field".equals(actionElement.getNodeName())) { + return new PropertyToField(modelWidget, actionElement); + } else if ("script".equals(actionElement.getNodeName())) { + return new Script(modelWidget, actionElement); + } else if ("service".equals(actionElement.getNodeName())) { + return new Service(modelWidget, actionElement); + } else if ("entity-one".equals(actionElement.getNodeName())) { + return new EntityOne(modelWidget, actionElement); + } else if ("entity-and".equals(actionElement.getNodeName())) { + return new EntityAnd(modelWidget, actionElement); + } else if ("entity-condition".equals(actionElement.getNodeName())) { + return new EntityCondition(modelWidget, actionElement); + } else if ("get-related-one".equals(actionElement.getNodeName())) { + return new GetRelatedOne(modelWidget, actionElement); + } else if ("get-related".equals(actionElement.getNodeName())) { + return new GetRelated(modelWidget, actionElement); + } else { + throw new IllegalArgumentException("Action element not supported with name: " + actionElement.getNodeName()); + } + } + + public static List<ModelAction> readSubActions(ModelWidget modelWidget, Element parentElement) { + List<? extends Element> actionElementList = UtilXml.childElementList(parentElement); + List<ModelAction> actions = new ArrayList<ModelAction>(actionElementList.size()); + for (Element actionElement : actionElementList) { + actions.add(newInstance(modelWidget, actionElement)); + } + return Collections.unmodifiableList(actions); + } + + /** + * Executes the actions contained in <code>actions</code>. + * + * @param actions + * @param context + */ + public static void runSubActions(List<ModelAction> actions, Map<String, Object> context) { + if (actions == null) + return; + for (ModelAction action : actions) { + if (Debug.verboseOn()) + Debug.logVerbose("Running action " + action.getClass().getName(), module); + try { + action.runAction(context); + } catch (GeneralException e) { + throw new RuntimeException(e); + } + } + } + + private final ModelWidget modelWidget; + + protected AbstractModelAction() { + // FIXME: This should not be null. + this.modelWidget = null; + } + + protected AbstractModelAction(ModelWidget modelWidget, Element actionElement) { + this.modelWidget = modelWidget; + if (Debug.verboseOn()) + Debug.logVerbose("Reading widget action with name: " + actionElement.getNodeName(), module); + } + + /** + * Returns the <code>ModelWidget</code> that contains the <actions> element. + * + * @return The <code>ModelWidget</code> that contains the <actions> element + */ + public ModelWidget getModelWidget() { + return modelWidget; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + ModelActionVisitor visitor = new XmlWidgetActionVisitor(sb); + try { + accept(visitor); + } catch (Exception e) { + Debug.logWarning(e, "Exception thrown in XmlWidgetActionVisitor: ", module); + } + return sb.toString(); + } + + /** + * Models the <entity-and> element. + * + * @see <code>widget-screen.xsd</code> + */ + public static class EntityAnd extends AbstractModelAction { + private final ByAndFinder finder; + + public EntityAnd(ModelWidget modelWidget, Element entityAndElement) { + super(modelWidget, entityAndElement); + finder = new ByAndFinder(entityAndElement); + } + + @Override + public void accept(ModelActionVisitor visitor) throws Exception { + visitor.visit(this); + } + + public ByAndFinder getFinder() { + return this.finder; + } + + @Override + public void runAction(Map<String, Object> context) { + try { + finder.runFind(context, WidgetWorker.getDelegator(context)); + } catch (GeneralException e) { + String errMsg = "Error doing entity query by condition: " + e.toString(); + Debug.logError(e, errMsg, module); + throw new IllegalArgumentException(errMsg); + } + } + } + + /** + * Models the <entity-condition> element. + * + * @see <code>widget-screen.xsd</code> + */ + public static class EntityCondition extends AbstractModelAction { + private final ByConditionFinder finder; + + public EntityCondition(ModelWidget modelWidget, Element entityConditionElement) { + super(modelWidget, entityConditionElement); + finder = new ByConditionFinder(entityConditionElement); + } + + @Override + public void accept(ModelActionVisitor visitor) throws Exception { + visitor.visit(this); + } + + public ByConditionFinder getFinder() { + return this.finder; + } + + @Override + public void runAction(Map<String, Object> context) { + try { + finder.runFind(context, WidgetWorker.getDelegator(context)); + } catch (GeneralException e) { + String errMsg = "Error doing entity query by condition: " + e.toString(); + Debug.logError(e, errMsg, module); + throw new IllegalArgumentException(errMsg); + } + } + } + + /** + * Models the <entity-one> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class EntityOne extends AbstractModelAction { + private final PrimaryKeyFinder finder; + + public EntityOne(ModelWidget modelWidget, Element entityOneElement) { + super(modelWidget, entityOneElement); + finder = new PrimaryKeyFinder(entityOneElement); + } + + @Override + public void accept(ModelActionVisitor visitor) throws Exception { + visitor.visit(this); + } + + public PrimaryKeyFinder getFinder() { + return this.finder; + } + + @Override + public void runAction(Map<String, Object> context) { + try { + finder.runFind(context, WidgetWorker.getDelegator(context)); + } catch (GeneralException e) { + String errMsg = "Error doing entity query by condition: " + e.toString(); + Debug.logError(e, errMsg, module); + throw new IllegalArgumentException(errMsg); + } + } + } + + /** + * Models the <get-related> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class GetRelated extends AbstractModelAction { + private final FlexibleMapAccessor<List<GenericValue>> listNameAcsr; + private final FlexibleMapAccessor<Map<String, Object>> mapAcsr; + private final FlexibleMapAccessor<List<String>> orderByListAcsr; + private final String relationName; + private final boolean useCache; + private final FlexibleMapAccessor<Object> valueNameAcsr; + + public GetRelated(ModelWidget modelWidget, Element getRelatedElement) { + super(modelWidget, getRelatedElement); + this.valueNameAcsr = FlexibleMapAccessor.getInstance(getRelatedElement.getAttribute("value-field")); + this.listNameAcsr = FlexibleMapAccessor.getInstance(getRelatedElement.getAttribute("list")); + this.relationName = getRelatedElement.getAttribute("relation-name"); + this.mapAcsr = FlexibleMapAccessor.getInstance(getRelatedElement.getAttribute("map")); + this.orderByListAcsr = FlexibleMapAccessor.getInstance(getRelatedElement.getAttribute("order-by-list")); + this.useCache = "true".equals(getRelatedElement.getAttribute("use-cache")); + } + + @Override + public void accept(ModelActionVisitor visitor) throws Exception { + visitor.visit(this); + } + + public String getRelationName() { + return this.relationName; + } + + @Override + public void runAction(Map<String, Object> context) { + Object valueObject = valueNameAcsr.get(context); + if (valueObject == null) { + Debug.logVerbose("Value not found with name: " + valueNameAcsr + ", not getting related...", module); + return; + } + if (!(valueObject instanceof GenericValue)) { + String errMsg = "Env variable for value-name " + valueNameAcsr.toString() + + " is not a GenericValue object; for the relation-name: " + relationName + "]"; + Debug.logError(errMsg, module); + throw new IllegalArgumentException(errMsg); + } + GenericValue value = (GenericValue) valueObject; + List<String> orderByNames = null; + if (!orderByListAcsr.isEmpty()) { + orderByNames = orderByListAcsr.get(context); + } + Map<String, Object> constraintMap = null; + if (!mapAcsr.isEmpty()) { + constraintMap = mapAcsr.get(context); + } + try { + listNameAcsr.put(context, value.getRelated(relationName, constraintMap, orderByNames, useCache)); + } catch (GenericEntityException e) { + String errMsg = "Problem getting related from entity with name " + value.getEntityName() + + " for the relation-name: " + relationName + ": " + e.getMessage(); + Debug.logError(e, errMsg, module); + throw new IllegalArgumentException(errMsg); + } + } + + public FlexibleMapAccessor<List<GenericValue>> getListNameAcsr() { + return listNameAcsr; + } + + public FlexibleMapAccessor<Map<String, Object>> getMapAcsr() { + return mapAcsr; + } + + public FlexibleMapAccessor<List<String>> getOrderByListAcsr() { + return orderByListAcsr; + } + + public boolean getUseCache() { + return useCache; + } + + public FlexibleMapAccessor<Object> getValueNameAcsr() { + return valueNameAcsr; + } + } + + /** + * Models the <get-related-one> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class GetRelatedOne extends AbstractModelAction { + private final String relationName; + private final FlexibleMapAccessor<Object> toValueNameAcsr; + private final boolean useCache; + private final FlexibleMapAccessor<Object> valueNameAcsr; + + public GetRelatedOne(ModelWidget modelWidget, Element getRelatedOneElement) { + super(modelWidget, getRelatedOneElement); + this.valueNameAcsr = FlexibleMapAccessor.getInstance(getRelatedOneElement.getAttribute("value-field")); + this.toValueNameAcsr = FlexibleMapAccessor.getInstance(getRelatedOneElement.getAttribute("to-value-field")); + this.relationName = getRelatedOneElement.getAttribute("relation-name"); + this.useCache = "true".equals(getRelatedOneElement.getAttribute("use-cache")); + } + + @Override + public void accept(ModelActionVisitor visitor) throws Exception { + visitor.visit(this); + } + + public String getRelationName() { + return this.relationName; + } + + @Override + public void runAction(Map<String, Object> context) { + Object valueObject = valueNameAcsr.get(context); + if (valueObject == null) { + Debug.logVerbose("Value not found with name: " + valueNameAcsr + ", not getting related...", module); + return; + } + if (!(valueObject instanceof GenericValue)) { + String errMsg = "Env variable for value-name " + valueNameAcsr.toString() + + " is not a GenericValue object; for the relation-name: " + relationName + "]"; + Debug.logError(errMsg, module); + throw new IllegalArgumentException(errMsg); + } + GenericValue value = (GenericValue) valueObject; + try { + toValueNameAcsr.put(context, value.getRelatedOne(relationName, useCache)); + } catch (GenericEntityException e) { + String errMsg = "Problem getting related one from entity with name " + value.getEntityName() + + " for the relation-name: " + relationName + ": " + e.getMessage(); + Debug.logError(e, errMsg, module); + throw new IllegalArgumentException(errMsg); + } + } + + public FlexibleMapAccessor<Object> getToValueNameAcsr() { + return toValueNameAcsr; + } + + public boolean getUseCache() { + return useCache; + } + + public FlexibleMapAccessor<Object> getValueNameAcsr() { + return valueNameAcsr; + } + } + + /** + * Models the <property-map> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class PropertyMap extends AbstractModelAction { + private final FlexibleStringExpander globalExdr; + private final FlexibleMapAccessor<ResourceBundleMapWrapper> mapNameAcsr; + private final FlexibleStringExpander resourceExdr; + + public PropertyMap(ModelWidget modelWidget, Element setElement) { + super(modelWidget, setElement); + this.resourceExdr = FlexibleStringExpander.getInstance(setElement.getAttribute("resource")); + this.mapNameAcsr = FlexibleMapAccessor.getInstance(setElement.getAttribute("map-name")); + this.globalExdr = FlexibleStringExpander.getInstance(setElement.getAttribute("global")); + } + + @Override + public void accept(ModelActionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public void runAction(Map<String, Object> context) { + String globalStr = this.globalExdr.expandString(context); + // default to false + boolean global = "true".equals(globalStr); + Locale locale = (Locale) context.get("locale"); + String resource = this.resourceExdr.expandString(context, locale); + ResourceBundleMapWrapper existingPropMap = this.mapNameAcsr.get(context); + if (existingPropMap == null) { + this.mapNameAcsr.put(context, UtilProperties.getResourceBundleMap(resource, locale, context)); + } else { + try { + existingPropMap.addBottomResourceBundle(resource); + } catch (IllegalArgumentException e) { + // log the error, but don't let it kill everything just for a typo or bad char in an l10n file + Debug.logError(e, "Error adding resource bundle [" + resource + "]: " + e.toString(), module); + } + } + if (global) { + Map<String, Object> globalCtx = UtilGenerics.checkMap(context.get("globalContext")); + if (globalCtx != null) { + ResourceBundleMapWrapper globalExistingPropMap = this.mapNameAcsr.get(globalCtx); + if (globalExistingPropMap == null) { + this.mapNameAcsr.put(globalCtx, UtilProperties.getResourceBundleMap(resource, locale, context)); + } else { + // is it the same object? if not add it in here too... + if (existingPropMap != globalExistingPropMap) { + try { + globalExistingPropMap.addBottomResourceBundle(resource); + } catch (IllegalArgumentException e) { + // log the error, but don't let it kill everything just for a typo or bad char in an l10n file + Debug.logError(e, "Error adding resource bundle [" + resource + "]: " + e.toString(), module); + } + } + } + } + } + } + + public FlexibleStringExpander getGlobalExdr() { + return globalExdr; + } + + public FlexibleMapAccessor<ResourceBundleMapWrapper> getMapNameAcsr() { + return mapNameAcsr; + } + + public FlexibleStringExpander getResourceExdr() { + return resourceExdr; + } + } + + /** + * Models the <property-to-field> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class PropertyToField extends AbstractModelAction { + private final FlexibleMapAccessor<List<? extends Object>> argListAcsr; + private final FlexibleStringExpander defaultExdr; + private final FlexibleMapAccessor<Object> fieldAcsr; + private final FlexibleStringExpander globalExdr; + private final boolean noLocale; + private final FlexibleStringExpander propertyExdr; + private final FlexibleStringExpander resourceExdr; + + public PropertyToField(ModelWidget modelWidget, Element setElement) { + super(modelWidget, setElement); + this.resourceExdr = FlexibleStringExpander.getInstance(setElement.getAttribute("resource")); + this.propertyExdr = FlexibleStringExpander.getInstance(setElement.getAttribute("property")); + this.fieldAcsr = FlexibleMapAccessor.getInstance(setElement.getAttribute("field")); + this.defaultExdr = FlexibleStringExpander.getInstance(setElement.getAttribute("default")); + this.noLocale = "true".equals(setElement.getAttribute("no-locale")); + this.argListAcsr = FlexibleMapAccessor.getInstance(setElement.getAttribute("arg-list-name")); + this.globalExdr = FlexibleStringExpander.getInstance(setElement.getAttribute("global")); + } + + @Override + public void accept(ModelActionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public void runAction(Map<String, Object> context) { + //String globalStr = this.globalExdr.expandString(context); + // default to false + //boolean global = "true".equals(globalStr); + Locale locale = (Locale) context.get("locale"); + String resource = this.resourceExdr.expandString(context, locale); + String property = this.propertyExdr.expandString(context, locale); + String value = null; + if (noLocale) { + value = EntityUtilProperties.getPropertyValue(resource, property, WidgetWorker.getDelegator(context)); + } else { + value = EntityUtilProperties.getMessage(resource, property, locale, WidgetWorker.getDelegator(context)); + } + if (UtilValidate.isEmpty(value)) { + value = this.defaultExdr.expandString(context); + } + // note that expanding the value string here will handle defaultValue and the string from + // the properties file; if we decide later that we don't want the string from the properties + // file to be expanded we should just expand the defaultValue at the beginning of this method. + value = FlexibleStringExpander.expandString(value, context); + if (!argListAcsr.isEmpty()) { + List<? extends Object> argList = argListAcsr.get(context); + if (UtilValidate.isNotEmpty(argList)) { + value = MessageFormat.format(value, argList.toArray()); + } + } + fieldAcsr.put(context, value); + } + + public FlexibleMapAccessor<List<? extends Object>> getArgListAcsr() { + return argListAcsr; + } + + public FlexibleStringExpander getDefaultExdr() { + return defaultExdr; + } + + public FlexibleMapAccessor<Object> getFieldAcsr() { + return fieldAcsr; + } + + public FlexibleStringExpander getGlobalExdr() { + return globalExdr; + } + + public boolean getNoLocale() { + return noLocale; + } + + public FlexibleStringExpander getPropertyExdr() { + return propertyExdr; + } + + public FlexibleStringExpander getResourceExdr() { + return resourceExdr; + } + } + + /** + * Models the <script> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class Script extends AbstractModelAction { + private final String location; + private final String method; + + public Script(ModelWidget modelWidget, Element scriptElement) { + super(modelWidget, scriptElement); + String scriptLocation = scriptElement.getAttribute("location"); + this.location = WidgetWorker.getScriptLocation(scriptLocation); + this.method = WidgetWorker.getScriptMethodName(scriptLocation); + } + + @Override + public void accept(ModelActionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public void runAction(Map<String, Object> context) throws GeneralException { + if (location.endsWith(".xml")) { + Map<String, Object> localContext = new HashMap<String, Object>(); + localContext.putAll(context); + DispatchContext ctx = WidgetWorker.getDispatcher(context).getDispatchContext(); + MethodContext methodContext = new MethodContext(ctx, localContext, null); + try { + SimpleMethod.runSimpleMethod(location, method, methodContext); + context.putAll(methodContext.getResults()); + } catch (MiniLangException e) { + throw new GeneralException("Error running simple method at location [" + location + "]", e); + } + } else { + ScriptUtil.executeScript(this.location, this.method, context); + } + } + + public String getLocation() { + return location; + } + + public String getMethod() { + return method; + } + } + + /** + * Models the <service> element. + * + * @see <code>widget-screen.xsd</code> + */ + public static class Service extends AbstractModelAction { + private final FlexibleStringExpander autoFieldMapExdr; + private final Map<FlexibleMapAccessor<Object>, Object> fieldMap; + private final FlexibleMapAccessor<Map<String, Object>> resultMapNameAcsr; + private final FlexibleStringExpander serviceNameExdr; + + public Service(ModelWidget modelWidget, Element serviceElement) { + super(modelWidget, serviceElement); + this.serviceNameExdr = FlexibleStringExpander.getInstance(serviceElement.getAttribute("service-name")); + this.resultMapNameAcsr = FlexibleMapAccessor.getInstance(serviceElement.getAttribute("result-map")); + this.autoFieldMapExdr = FlexibleStringExpander.getInstance(serviceElement.getAttribute("auto-field-map")); + this.fieldMap = EntityFinderUtil.makeFieldMap(serviceElement); + } + + @Override + public void accept(ModelActionVisitor visitor) throws Exception { + visitor.visit(this); + } + + public FlexibleStringExpander getServiceNameExdr() { + return this.serviceNameExdr; + } + + @Override + public void runAction(Map<String, Object> context) { + String serviceNameExpanded = this.serviceNameExdr.expandString(context); + if (UtilValidate.isEmpty(serviceNameExpanded)) { + throw new IllegalArgumentException("Service name was empty, expanded from: " + this.serviceNameExdr.getOriginal()); + } + String autoFieldMapString = this.autoFieldMapExdr.expandString(context); + try { + Map<String, Object> serviceContext = null; + if ("true".equals(autoFieldMapString)) { + DispatchContext dc = WidgetWorker.getDispatcher(context).getDispatchContext(); + // try a map called "parameters", try it first so values from here are overriden by values in the main context + Map<String, Object> combinedMap = new HashMap<String, Object>(); + Map<String, Object> parametersObj = UtilGenerics.toMap(context.get("parameters")); + if (parametersObj != null) { + combinedMap.putAll(parametersObj); + } + combinedMap.putAll(context); + serviceContext = dc.makeValidContext(serviceNameExpanded, ModelService.IN_PARAM, combinedMap); + } else if (UtilValidate.isNotEmpty(autoFieldMapString) && !"false".equals(autoFieldMapString)) { + FlexibleMapAccessor<Object> fieldFma = FlexibleMapAccessor.getInstance(autoFieldMapString); + Map<String, Object> autoFieldMap = UtilGenerics.toMap(fieldFma.get(context)); + if (autoFieldMap != null) { + serviceContext = WidgetWorker.getDispatcher(context).getDispatchContext() + .makeValidContext(serviceNameExpanded, ModelService.IN_PARAM, autoFieldMap); + } + } + if (serviceContext == null) { + serviceContext = new HashMap<String, Object>(); + } + if (this.fieldMap != null) { + EntityFinderUtil.expandFieldMapToContext(this.fieldMap, context, serviceContext); + } + Map<String, Object> result = WidgetWorker.getDispatcher(context).runSync(serviceNameExpanded, serviceContext); + if (!this.resultMapNameAcsr.isEmpty()) { + this.resultMapNameAcsr.put(context, result); + String queryString = (String) result.get("queryString"); + context.put("queryString", queryString); + context.put("queryStringMap", result.get("queryStringMap")); + if (UtilValidate.isNotEmpty(queryString)) { + try { + String queryStringEncoded = queryString.replaceAll("&", "%26"); + context.put("queryStringEncoded", queryStringEncoded); + } catch (PatternSyntaxException e) { + + } + } + } else { + context.putAll(result); + } + } catch (GenericServiceException e) { + String errMsg = "Error calling service with name " + serviceNameExpanded + ": " + e.toString(); + Debug.logError(e, errMsg, module); + throw new IllegalArgumentException(errMsg); + } + } + + public FlexibleStringExpander getAutoFieldMapExdr() { + return autoFieldMapExdr; + } + + public Map<FlexibleMapAccessor<Object>, Object> getFieldMap() { + return fieldMap; + } + + public FlexibleMapAccessor<Map<String, Object>> getResultMapNameAcsr() { + return resultMapNameAcsr; + } + } + + /** + * Models the <set> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class SetField extends AbstractModelAction { + private final FlexibleStringExpander defaultExdr; + private final FlexibleMapAccessor<Object> field; + private final FlexibleMapAccessor<Object> fromField; + private final String fromScope; + private final FlexibleStringExpander globalExdr; + private final String toScope; + private final String type; + private final FlexibleStringExpander valueExdr; + + public SetField(ModelWidget modelWidget, Element setElement) { + super(modelWidget, setElement); + this.field = FlexibleMapAccessor.getInstance(setElement.getAttribute("field")); + this.fromField = FlexibleMapAccessor.getInstance(setElement.getAttribute("from-field")); + this.valueExdr = FlexibleStringExpander.getInstance(setElement.getAttribute("value")); + this.defaultExdr = FlexibleStringExpander.getInstance(setElement.getAttribute("default-value")); + this.globalExdr = FlexibleStringExpander.getInstance(setElement.getAttribute("global")); + this.type = setElement.getAttribute("type"); + this.toScope = setElement.getAttribute("to-scope"); + this.fromScope = setElement.getAttribute("from-scope"); + if (!this.fromField.isEmpty() && !this.valueExdr.isEmpty()) { + throw new IllegalArgumentException("Cannot specify a from-field [" + setElement.getAttribute("from-field") + + "] and a value [" + setElement.getAttribute("value") + "] on the set action in a widget"); + } + } + + @Override + public void accept(ModelActionVisitor visitor) throws Exception { + visitor.visit(this); + } + + public Object getInMemoryPersistedFromField(Object storeAgent, Map<String, Object> context) { + Object newValue = null; + String originalName = this.fromField.getOriginalName(); + List<String> currentWidgetTrail = UtilGenerics.toList(context.get("_WIDGETTRAIL_")); + List<String> trailList = new ArrayList<String>(); + if (currentWidgetTrail != null) { + trailList.addAll(currentWidgetTrail); + } + for (int i = trailList.size(); i >= 0; i--) { + List<String> subTrail = trailList.subList(0, i); + String newKey = null; + if (subTrail.size() > 0) + newKey = StringUtil.join(subTrail, "|") + "|" + originalName; + else + newKey = originalName; + if (storeAgent instanceof ServletContext) { + newValue = ((ServletContext) storeAgent).getAttribute(newKey); + } else if (storeAgent instanceof HttpSession) { + newValue = ((HttpSession) storeAgent).getAttribute(newKey); + } + if (newValue != null) { + break; + } + } + return newValue; + } + + @SuppressWarnings("rawtypes") + @Override + public void runAction(Map<String, Object> context) { + String globalStr = this.globalExdr.expandString(context); + // default to false + boolean global = "true".equals(globalStr); + Object newValue = null; + if (this.fromScope != null && this.fromScope.equals("user")) { + if (!this.fromField.isEmpty()) { + HttpSession session = (HttpSession) context.get("session"); + newValue = getInMemoryPersistedFromField(session, context); + if (Debug.verboseOn()) + Debug.logVerbose("In user getting value for field from [" + this.fromField.getOriginalName() + "]: " + + newValue, module); + } else if (!this.valueExdr.isEmpty()) { + newValue = this.valueExdr.expand(context); + } + } else if (this.fromScope != null && this.fromScope.equals("application")) { + if (!this.fromField.isEmpty()) { + ServletContext servletContext = (ServletContext) context.get("application"); + newValue = getInMemoryPersistedFromField(servletContext, context); + if (Debug.verboseOn()) + Debug.logVerbose("In application getting value for field from [" + this.fromField.getOriginalName() + + "]: " + newValue, module); + } else if (!this.valueExdr.isEmpty()) { + newValue = this.valueExdr.expandString(context); + } + } else { + if (!this.fromField.isEmpty()) { + newValue = this.fromField.get(context); + if (Debug.verboseOn()) + Debug.logVerbose("Getting value for field from [" + this.fromField.getOriginalName() + "]: " + newValue, + module); + } else if (!this.valueExdr.isEmpty()) { + newValue = this.valueExdr.expand(context); + } + } + // If newValue is still empty, use the default value + if (ObjectType.isEmpty(newValue) && !this.defaultExdr.isEmpty()) { + newValue = this.defaultExdr.expand(context); + } + if (UtilValidate.isNotEmpty(this.type)) { + if ("NewMap".equals(this.type)) { + newValue = new HashMap(); + } else if ("NewList".equals(this.type)) { + newValue = new LinkedList(); + } else { + try { + newValue = ObjectType.simpleTypeConvert(newValue, this.type, null, (TimeZone) context.get("timeZone"), + (Locale) context.get("locale"), true); + } catch (GeneralException e) { + String errMsg = "Could not convert field value for the field: [" + this.field.getOriginalName() + + "] to the [" + this.type + "] type for the value [" + newValue + "]: " + e.toString(); + Debug.logError(e, errMsg, module); + throw new IllegalArgumentException(errMsg); + } + } + } + if (this.toScope != null && this.toScope.equals("user")) { + String originalName = this.field.getOriginalName(); + List<String> currentWidgetTrail = UtilGenerics.toList(context.get("_WIDGETTRAIL_")); + String newKey = ""; + if (currentWidgetTrail != null) { + newKey = StringUtil.join(currentWidgetTrail, "|"); + } + if (UtilValidate.isNotEmpty(newKey)) { + newKey += "|"; + } + newKey += originalName; + HttpSession session = (HttpSession) context.get("session"); + session.setAttribute(newKey, newValue); + if (Debug.verboseOn()) + Debug.logVerbose("In user setting value for field from [" + this.field.getOriginalName() + "]: " + newValue, + module); + } else if (this.toScope != null && this.toScope.equals("application")) { + String originalName = this.field.getOriginalName(); + List<String> currentWidgetTrail = UtilGenerics.toList(context.get("_WIDGETTRAIL_")); + String newKey = ""; + if (currentWidgetTrail != null) { + newKey = StringUtil.join(currentWidgetTrail, "|"); + } + if (UtilValidate.isNotEmpty(newKey)) { + newKey += "|"; + } + newKey += originalName; + ServletContext servletContext = (ServletContext) context.get("application"); + servletContext.setAttribute(newKey, newValue); + if (Debug.verboseOn()) + Debug.logVerbose("In application setting value for field from [" + this.field.getOriginalName() + "]: " + + newValue, module); + } else { + // only do this if it is not global, if global ONLY put it in the global context + if (!global) { + if (Debug.verboseOn()) + Debug.logVerbose("Setting field [" + this.field.getOriginalName() + "] to value: " + newValue, module); + this.field.put(context, newValue); + } + } + if (global) { + Map<String, Object> globalCtx = UtilGenerics.checkMap(context.get("globalContext")); + if (globalCtx != null) { + this.field.put(globalCtx, newValue); + } else { + this.field.put(context, newValue); + } + } + // this is a hack for backward compatibility with the JPublish page object + Map<String, Object> page = UtilGenerics.checkMap(context.get("page")); + if (page != null) { + this.field.put(page, newValue); + } + } + + public FlexibleStringExpander getDefaultExdr() { + return defaultExdr; + } + + public FlexibleMapAccessor<Object> getField() { + return field; + } + + public FlexibleMapAccessor<Object> getFromField() { + return fromField; + } + + public String getFromScope() { + return fromScope; + } + + public FlexibleStringExpander getGlobalExdr() { + return globalExdr; + } + + public String getToScope() { + return toScope; + } + + public String getType() { + return type; + } + + public FlexibleStringExpander getValueExdr() { + return valueExdr; + } + } +} Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/AbstractModelCondition.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/AbstractModelCondition.java?rev=1652638&view=auto ============================================================================== --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/AbstractModelCondition.java (added) +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/AbstractModelCondition.java Sat Jan 17 16:47:23 2015 @@ -0,0 +1,828 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.ofbiz.widget; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; + +import org.apache.oro.text.regex.MalformedPatternException; +import org.apache.oro.text.regex.Pattern; +import org.apache.oro.text.regex.PatternMatcher; +import org.apache.oro.text.regex.Perl5Matcher; +import org.ofbiz.base.util.Debug; +import org.ofbiz.base.util.GeneralException; +import org.ofbiz.base.util.ObjectType; +import org.ofbiz.base.util.PatternFactory; +import org.ofbiz.base.util.UtilGenerics; +import org.ofbiz.base.util.UtilValidate; +import org.ofbiz.base.util.UtilXml; +import org.ofbiz.base.util.collections.FlexibleMapAccessor; +import org.ofbiz.base.util.string.FlexibleStringExpander; +import org.ofbiz.entity.GenericValue; +import org.ofbiz.entityext.permission.EntityPermissionChecker; +import org.ofbiz.minilang.operation.BaseCompare; +import org.ofbiz.security.Security; +import org.ofbiz.service.DispatchContext; +import org.ofbiz.service.GenericServiceException; +import org.ofbiz.service.LocalDispatcher; +import org.ofbiz.service.ModelService; +import org.ofbiz.service.ServiceUtil; +import org.ofbiz.widget.xml.*; +import org.w3c.dom.Element; + +/** + * Abstract base class for the condition models. + */ +@SuppressWarnings("serial") +public abstract class AbstractModelCondition implements Serializable, ModelCondition { + + /* + * ----------------------------------------------------------------------- * + * DEVELOPERS PLEASE READ + * ----------------------------------------------------------------------- * + * + * This model is intended to be a read-only data structure that represents + * an XML element. Outside of object construction, the class should not + * have any behaviors. + * + * Instances of this class will be shared by multiple threads - therefore + * it is immutable. DO NOT CHANGE THE OBJECT'S STATE AT RUN TIME! + * + */ + + public static final String module = AbstractModelCondition.class.getName(); + public static final ModelConditionFactory DEFAULT_CONDITION_FACTORY = new DefaultConditionFactory(); + + public static List<ModelCondition> readSubConditions(ModelConditionFactory factory, ModelWidget modelWidget, + Element conditionElement) { + List<? extends Element> subElementList = UtilXml.childElementList(conditionElement); + List<ModelCondition> condList = new ArrayList<ModelCondition>(subElementList.size()); + for (Element subElement : subElementList) { + condList.add(factory.newInstance(modelWidget, subElement)); + } + return Collections.unmodifiableList(condList); + } + + private final ModelWidget modelWidget; + + protected AbstractModelCondition(ModelConditionFactory factory, ModelWidget modelWidget, Element conditionElement) { + this.modelWidget = modelWidget; + } + + public ModelWidget getModelWidget() { + return modelWidget; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + ModelConditionVisitor visitor = new XmlWidgetConditionVisitor(sb); + try { + accept(visitor); + } catch (Exception e) { + Debug.logWarning(e, "Exception thrown in XmlWidgetConditionVisitor: ", module); + } + return sb.toString(); + } + + /** + * Models the <and> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class And extends AbstractModelCondition { + private final List<ModelCondition> subConditions; + + private And(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) { + super(factory, modelWidget, condElement); + this.subConditions = readSubConditions(factory, modelWidget, condElement); + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public boolean eval(Map<String, Object> context) { + // return false for the first one in the list that is false, basic and algo + for (ModelCondition subCondition : this.subConditions) { + if (!subCondition.eval(context)) { + return false; + } + } + return true; + } + + public List<ModelCondition> getSubConditions() { + return subConditions; + } + } + + /** + * A <code>ModelCondition</code> factory. This factory handles elements + * common to all widgets that support conditions. Widgets that have + * specialized conditions can extend this class. + * + */ + public static class DefaultConditionFactory implements ModelConditionFactory { + public static final ModelCondition TRUE = new ModelCondition() { + @Override + public boolean eval(Map<String, Object> context) { + return true; + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + } + }; + + public static final ModelCondition FALSE = new ModelCondition() { + @Override + public boolean eval(Map<String, Object> context) { + return false; + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + } + }; + + public ModelCondition newInstance(ModelWidget modelWidget, Element conditionElement) { + return newInstance(this, modelWidget, conditionElement); + } + + // TODO: Test extended factory + protected ModelCondition newInstance(ModelConditionFactory factory, ModelWidget modelWidget, Element conditionElement) { + if (conditionElement == null) { + return TRUE; + } + String nodeName = conditionElement.getNodeName(); + if ("and".equals(nodeName)) { + return new And(factory, modelWidget, conditionElement); + } else if ("xor".equals(nodeName)) { + return new Xor(factory, modelWidget, conditionElement); + } else if ("or".equals(nodeName)) { + return new Or(factory, modelWidget, conditionElement); + } else if ("not".equals(nodeName)) { + return new Not(factory, modelWidget, conditionElement); + } else if ("if-service-permission".equals(nodeName)) { + return new IfServicePermission(factory, modelWidget, conditionElement); + } else if ("if-has-permission".equals(nodeName)) { + return new IfHasPermission(factory, modelWidget, conditionElement); + } else if ("if-validate-method".equals(nodeName)) { + return new IfValidateMethod(factory, modelWidget, conditionElement); + } else if ("if-compare".equals(nodeName)) { + return new IfCompare(factory, modelWidget, conditionElement); + } else if ("if-compare-field".equals(nodeName)) { + return new IfCompareField(factory, modelWidget, conditionElement); + } else if ("if-regexp".equals(nodeName)) { + return new IfRegexp(factory, modelWidget, conditionElement); + } else if ("if-empty".equals(nodeName)) { + return new IfEmpty(factory, modelWidget, conditionElement); + } else if ("if-entity-permission".equals(nodeName)) { + return new IfEntityPermission(factory, modelWidget, conditionElement); + } else { + throw new IllegalArgumentException("Condition element not supported with name: " + conditionElement.getNodeName()); + } + } + } + + /** + * Models the <if-compare> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class IfCompare extends AbstractModelCondition { + private final FlexibleMapAccessor<Object> fieldAcsr; + private final FlexibleStringExpander formatExdr; + private final String operator; + private final String type; + private final FlexibleStringExpander valueExdr; + + private IfCompare(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) { + super(factory, modelWidget, condElement); + String fieldAcsr = condElement.getAttribute("field"); + if (fieldAcsr.isEmpty()) + fieldAcsr = condElement.getAttribute("field-name"); + this.fieldAcsr = FlexibleMapAccessor.getInstance(fieldAcsr); + this.valueExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("value")); + this.operator = condElement.getAttribute("operator"); + this.type = condElement.getAttribute("type"); + this.formatExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("format")); + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public boolean eval(Map<String, Object> context) { + String value = this.valueExdr.expandString(context); + String format = this.formatExdr.expandString(context); + Object fieldVal = this.fieldAcsr.get(context); + // always use an empty string by default + if (fieldVal == null) { + fieldVal = ""; + } + List<Object> messages = new LinkedList<Object>(); + Boolean resultBool = BaseCompare.doRealCompare(fieldVal, value, operator, type, format, messages, null, null, true); + if (messages.size() > 0) { + messages.add(0, "Error with comparison in if-compare between field [" + fieldAcsr.toString() + "] with value [" + + fieldVal + "] and value [" + value + "] with operator [" + operator + "] and type [" + type + "]: "); + + StringBuilder fullString = new StringBuilder(); + for (Object item : messages) { + fullString.append(item.toString()); + } + Debug.logWarning(fullString.toString(), module); + throw new IllegalArgumentException(fullString.toString()); + } + return resultBool.booleanValue(); + } + + public FlexibleMapAccessor<Object> getFieldAcsr() { + return fieldAcsr; + } + + public FlexibleStringExpander getFormatExdr() { + return formatExdr; + } + + public String getOperator() { + return operator; + } + + public String getType() { + return type; + } + + public FlexibleStringExpander getValueExdr() { + return valueExdr; + } + } + + /** + * Models the <if-compare-field> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class IfCompareField extends AbstractModelCondition { + private final FlexibleMapAccessor<Object> fieldAcsr; + private final FlexibleStringExpander formatExdr; + private final String operator; + private final FlexibleMapAccessor<Object> toFieldAcsr; + private final String type; + + private IfCompareField(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) { + super(factory, modelWidget, condElement); + String fieldAcsr = condElement.getAttribute("field"); + if (fieldAcsr.isEmpty()) + fieldAcsr = condElement.getAttribute("field-name"); + this.fieldAcsr = FlexibleMapAccessor.getInstance(fieldAcsr); + String toFieldAcsr = condElement.getAttribute("to-field"); + if (toFieldAcsr.isEmpty()) + toFieldAcsr = condElement.getAttribute("to-field-name"); + this.toFieldAcsr = FlexibleMapAccessor.getInstance(toFieldAcsr); + this.operator = condElement.getAttribute("operator"); + this.type = condElement.getAttribute("type"); + this.formatExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("format")); + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public boolean eval(Map<String, Object> context) { + String format = this.formatExdr.expandString(context); + Object fieldVal = this.fieldAcsr.get(context); + Object toFieldVal = this.toFieldAcsr.get(context); + // always use an empty string by default + if (fieldVal == null) { + fieldVal = ""; + } + List<Object> messages = new LinkedList<Object>(); + Boolean resultBool = BaseCompare.doRealCompare(fieldVal, toFieldVal, operator, type, format, messages, null, null, + false); + if (messages.size() > 0) { + messages.add(0, "Error with comparison in if-compare-field between field [" + fieldAcsr.toString() + + "] with value [" + fieldVal + "] and to-field [" + toFieldAcsr.toString() + "] with value [" + + toFieldVal + "] with operator [" + operator + "] and type [" + type + "]: "); + + StringBuilder fullString = new StringBuilder(); + for (Object item : messages) { + fullString.append(item.toString()); + } + Debug.logWarning(fullString.toString(), module); + throw new IllegalArgumentException(fullString.toString()); + } + return resultBool.booleanValue(); + } + + public FlexibleMapAccessor<Object> getFieldAcsr() { + return fieldAcsr; + } + + public FlexibleStringExpander getFormatExdr() { + return formatExdr; + } + + public String getOperator() { + return operator; + } + + public FlexibleMapAccessor<Object> getToFieldAcsr() { + return toFieldAcsr; + } + + public String getType() { + return type; + } + } + + /** + * Models the <if-empty> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class IfEmpty extends AbstractModelCondition { + private final FlexibleMapAccessor<Object> fieldAcsr; + + private IfEmpty(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) { + super(factory, modelWidget, condElement); + String fieldAcsr = condElement.getAttribute("field"); + if (fieldAcsr.isEmpty()) + fieldAcsr = condElement.getAttribute("field-name"); + this.fieldAcsr = FlexibleMapAccessor.getInstance(fieldAcsr); + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public boolean eval(Map<String, Object> context) { + Object fieldVal = this.fieldAcsr.get(context); + return ObjectType.isEmpty(fieldVal); + } + + public FlexibleMapAccessor<Object> getFieldAcsr() { + return fieldAcsr; + } + + } + + /** + * Models the <if-entity-permission> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class IfEntityPermission extends AbstractModelCondition { + private final EntityPermissionChecker permissionChecker; + + private IfEntityPermission(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) { + super(factory, modelWidget, condElement); + this.permissionChecker = new EntityPermissionChecker(condElement); + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public boolean eval(Map<String, Object> context) { + return permissionChecker.runPermissionCheck(context); + } + + public EntityPermissionChecker getPermissionChecker() { + return permissionChecker; + } + } + + /** + * Models the <if-has-permission> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class IfHasPermission extends AbstractModelCondition { + private final FlexibleStringExpander actionExdr; + private final FlexibleStringExpander permissionExdr; + + private IfHasPermission(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) { + super(factory, modelWidget, condElement); + this.permissionExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("permission")); + this.actionExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("action")); + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public boolean eval(Map<String, Object> context) { + // if no user is logged in, treat as if the user does not have permission + GenericValue userLogin = (GenericValue) context.get("userLogin"); + if (userLogin != null) { + String permission = permissionExdr.expandString(context); + String action = actionExdr.expandString(context); + Security security = (Security) context.get("security"); + if (UtilValidate.isNotEmpty(action)) { + // run hasEntityPermission + if (security.hasEntityPermission(permission, action, userLogin)) { + return true; + } + } else { + // run hasPermission + if (security.hasPermission(permission, userLogin)) { + return true; + } + } + } + return false; + } + + public FlexibleStringExpander getActionExdr() { + return actionExdr; + } + + public FlexibleStringExpander getPermissionExdr() { + return permissionExdr; + } + } + + /** + * Models the <if-regexp> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class IfRegexp extends AbstractModelCondition { + private final FlexibleStringExpander exprExdr; + private final FlexibleMapAccessor<Object> fieldAcsr; + + private IfRegexp(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) { + super(factory, modelWidget, condElement); + String fieldAcsr = condElement.getAttribute("field"); + if (fieldAcsr.isEmpty()) + fieldAcsr = condElement.getAttribute("field-name"); + this.fieldAcsr = FlexibleMapAccessor.getInstance(fieldAcsr); + this.exprExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("expr")); + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public boolean eval(Map<String, Object> context) { + Object fieldVal = this.fieldAcsr.get(context); + String expr = this.exprExdr.expandString(context); + Pattern pattern; + try { + pattern = PatternFactory.createOrGetPerl5CompiledPattern(expr, true); + } catch (MalformedPatternException e) { + String errMsg = "Error in evaluation in if-regexp in screen: " + e.toString(); + Debug.logError(e, errMsg, module); + throw new IllegalArgumentException(errMsg); + } + String fieldString = null; + try { + fieldString = (String) ObjectType.simpleTypeConvert(fieldVal, "String", null, (TimeZone) context.get("timeZone"), + (Locale) context.get("locale"), true); + } catch (GeneralException e) { + Debug.logError(e, "Could not convert object to String, using empty String", module); + } + // always use an empty string by default + if (fieldString == null) + fieldString = ""; + PatternMatcher matcher = new Perl5Matcher(); + return matcher.matches(fieldString, pattern); + } + + public FlexibleStringExpander getExprExdr() { + return exprExdr; + } + + public FlexibleMapAccessor<Object> getFieldAcsr() { + return fieldAcsr; + } + } + + /** + * Models the <if-service-permission> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class IfServicePermission extends AbstractModelCondition { + private final FlexibleStringExpander actionExdr; + private final FlexibleStringExpander ctxMapExdr; + private final FlexibleStringExpander resExdr; + private final FlexibleStringExpander serviceExdr; + + private IfServicePermission(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) { + super(factory, modelWidget, condElement); + this.serviceExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("service-name")); + this.actionExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("main-action")); + this.ctxMapExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("context-map")); + this.resExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("resource-description")); + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public boolean eval(Map<String, Object> context) { + // if no user is logged in, treat as if the user does not have permission + GenericValue userLogin = (GenericValue) context.get("userLogin"); + if (userLogin != null) { + String serviceName = serviceExdr.expandString(context); + String mainAction = actionExdr.expandString(context); + String contextMap = ctxMapExdr.expandString(context); + String resource = resExdr.expandString(context); + if (UtilValidate.isEmpty(resource)) { + resource = serviceName; + } + if (UtilValidate.isEmpty(serviceName)) { + Debug.logWarning("No permission service-name specified!", module); + return false; + } + Map<String, Object> serviceContext = UtilGenerics.toMap(context.get(contextMap)); + if (serviceContext != null) { + // copy the required internal fields + serviceContext.put("userLogin", context.get("userLogin")); + serviceContext.put("locale", context.get("locale")); + } else { + serviceContext = context; + } + // get the service engine objects + LocalDispatcher dispatcher = (LocalDispatcher) context.get("dispatcher"); + DispatchContext dctx = dispatcher.getDispatchContext(); + // get the service + ModelService permService; + try { + permService = dctx.getModelService(serviceName); + } catch (GenericServiceException e) { + Debug.logError(e, module); + return false; + } + if (permService != null) { + // build the context + Map<String, Object> svcCtx = permService.makeValid(serviceContext, ModelService.IN_PARAM); + svcCtx.put("resourceDescription", resource); + if (UtilValidate.isNotEmpty(mainAction)) { + svcCtx.put("mainAction", mainAction); + } + // invoke the service + Map<String, Object> resp; + try { + resp = dispatcher.runSync(permService.name, svcCtx, 300, true); + } catch (GenericServiceException e) { + Debug.logError(e, module); + return false; + } + if (ServiceUtil.isError(resp) || ServiceUtil.isFailure(resp)) { + Debug.logError(ServiceUtil.getErrorMessage(resp), module); + return false; + } + Boolean hasPermission = (Boolean) resp.get("hasPermission"); + if (hasPermission != null) { + return hasPermission.booleanValue(); + } + } + } + return false; + } + + public FlexibleStringExpander getActionExdr() { + return actionExdr; + } + + public FlexibleStringExpander getCtxMapExdr() { + return ctxMapExdr; + } + + public FlexibleStringExpander getResExdr() { + return resExdr; + } + + public FlexibleStringExpander getServiceExdr() { + return serviceExdr; + } + } + + /** + * Models the <if-validate-method> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class IfValidateMethod extends AbstractModelCondition { + private final FlexibleStringExpander classExdr; + private final FlexibleMapAccessor<Object> fieldAcsr; + private final FlexibleStringExpander methodExdr; + + private IfValidateMethod(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) { + super(factory, modelWidget, condElement); + String fieldAcsr = condElement.getAttribute("field"); + if (fieldAcsr.isEmpty()) + fieldAcsr = condElement.getAttribute("field-name"); + this.fieldAcsr = FlexibleMapAccessor.getInstance(fieldAcsr); + this.methodExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("method")); + this.classExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("class")); + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public boolean eval(Map<String, Object> context) { + String methodName = this.methodExdr.expandString(context); + String className = this.classExdr.expandString(context); + Object fieldVal = this.fieldAcsr.get(context); + String fieldString = null; + if (fieldVal != null) { + try { + fieldString = (String) ObjectType.simpleTypeConvert(fieldVal, "String", null, + (TimeZone) context.get("timeZone"), (Locale) context.get("locale"), true); + } catch (GeneralException e) { + Debug.logError(e, "Could not convert object to String, using empty String", module); + } + } + // always use an empty string by default + if (fieldString == null) + fieldString = ""; + Class<?>[] paramTypes = new Class[] { String.class }; + Object[] params = new Object[] { fieldString }; + Class<?> valClass; + try { + valClass = ObjectType.loadClass(className); + } catch (ClassNotFoundException cnfe) { + Debug.logError("Could not find validation class: " + className, module); + return false; + } + Method valMethod; + try { + valMethod = valClass.getMethod(methodName, paramTypes); + } catch (NoSuchMethodException cnfe) { + Debug.logError("Could not find validation method: " + methodName + " of class " + className, module); + return false; + } + Boolean resultBool = Boolean.FALSE; + try { + resultBool = (Boolean) valMethod.invoke(null, params); + } catch (Exception e) { + Debug.logError(e, "Error in IfValidationMethod " + methodName + " of class " + className + + ", defaulting to false ", module); + } + return resultBool.booleanValue(); + } + + public FlexibleStringExpander getClassExdr() { + return classExdr; + } + + public FlexibleMapAccessor<Object> getFieldAcsr() { + return fieldAcsr; + } + + public FlexibleStringExpander getMethodExdr() { + return methodExdr; + } + + } + + /** + * Models the <not> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class Not extends AbstractModelCondition { + private final ModelCondition subCondition; + + private Not(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) { + super(factory, modelWidget, condElement); + Element firstChildElement = UtilXml.firstChildElement(condElement); + this.subCondition = factory.newInstance(modelWidget, firstChildElement); + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public boolean eval(Map<String, Object> context) { + return !this.subCondition.eval(context); + } + + public ModelCondition getSubCondition() { + return subCondition; + } + } + + /** + * Models the <or> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class Or extends AbstractModelCondition { + private final List<ModelCondition> subConditions; + + private Or(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) { + super(factory, modelWidget, condElement); + this.subConditions = readSubConditions(factory, modelWidget, condElement); + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public boolean eval(Map<String, Object> context) { + // return true for the first one in the list that is true, basic or algo + for (ModelCondition subCondition : this.subConditions) { + if (subCondition.eval(context)) { + return true; + } + } + return false; + } + + public List<ModelCondition> getSubConditions() { + return subConditions; + } + } + + /** + * Models the <xor> element. + * + * @see <code>widget-common.xsd</code> + */ + public static class Xor extends AbstractModelCondition { + private final List<ModelCondition> subConditions; + + private Xor(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) { + super(factory, modelWidget, condElement); + this.subConditions = readSubConditions(factory, modelWidget, condElement); + } + + @Override + public void accept(ModelConditionVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public boolean eval(Map<String, Object> context) { + // if more than one is true stop immediately and return false; if all are false return false; if only one is true return true + boolean foundOneTrue = false; + for (ModelCondition subCondition : this.subConditions) { + if (subCondition.eval(context)) { + if (foundOneTrue) { + // now found two true, so return false + return false; + } else { + foundOneTrue = true; + } + } + } + return foundOneTrue; + } + + public List<ModelCondition> getSubConditions() { + return subConditions; + } + } +} |
Free forum by Nabble | Edit this page |