/******************************************************************************* | |
* 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.model; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.ListIterator; | |
import java.util.Map; | |
import java.util.regex.PatternSyntaxException; | |
import org.ofbiz.base.util.Debug; | |
import org.ofbiz.base.util.GeneralException; | |
import org.ofbiz.base.util.ScriptUtil; | |
import org.ofbiz.base.util.UtilFormatOut; | |
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.finder.ByAndFinder; | |
import org.ofbiz.entity.finder.ByConditionFinder; | |
import org.ofbiz.entity.finder.EntityFinderUtil; | |
import org.ofbiz.entity.util.EntityListIterator; | |
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.WidgetWorker; | |
import org.ofbiz.widget.model.ModelTree.ModelNode; | |
import org.w3c.dom.Document; | |
import org.w3c.dom.Element; | |
/** | |
* Abstract tree action. | |
*/ | |
@SuppressWarnings("serial") | |
public abstract class ModelTreeAction extends AbstractModelAction { | |
/* | |
* ----------------------------------------------------------------------- * | |
* 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 = ModelTreeAction.class.getName(); | |
public static List<ModelAction> readNodeActions(ModelNode modelNode, Element actionsElement) { | |
List<? extends Element> actionElementList = UtilXml.childElementList(actionsElement); | |
List<ModelAction> actions = new ArrayList<ModelAction>(actionElementList.size()); | |
for (Element actionElement : actionElementList) { | |
if ("service".equals(actionElement.getNodeName())) { | |
actions.add(new Service(modelNode, actionElement)); | |
} else if ("script".equals(actionElement.getNodeName())) { | |
actions.add(new Script(modelNode, actionElement)); | |
} else { | |
actions.add(AbstractModelAction.newInstance(modelNode, actionElement)); | |
} | |
} | |
return actions; | |
} | |
public static List<ModelAction> readSubNodeActions(ModelNode.ModelSubNode modelSubNode, Element actionsElement) { | |
List<? extends Element> actionElementList = UtilXml.childElementList(actionsElement); | |
List<ModelAction> actions = new ArrayList<ModelAction>(actionElementList.size()); | |
for (Element actionElement : actionElementList) { | |
if ("service".equals(actionElement.getNodeName())) { | |
actions.add(new Service(modelSubNode, actionElement)); | |
} else if ("entity-and".equals(actionElement.getNodeName())) { | |
actions.add(new EntityAnd(modelSubNode, actionElement)); | |
} else if ("entity-condition".equals(actionElement.getNodeName())) { | |
actions.add(new EntityCondition(modelSubNode, actionElement)); | |
} else if ("script".equals(actionElement.getNodeName())) { | |
actions.add(new Script(modelSubNode, actionElement)); | |
} else { | |
actions.add(AbstractModelAction.newInstance(modelSubNode, actionElement)); | |
} | |
} | |
return actions; | |
} | |
private final ModelNode.ModelSubNode modelSubNode; | |
private final ModelTree modelTree; | |
protected ModelTreeAction(ModelNode modelNode, Element actionElement) { | |
if (Debug.verboseOn()) | |
Debug.logVerbose("Reading Tree action with name: " + actionElement.getNodeName(), module); | |
this.modelTree = modelNode.getModelTree(); | |
this.modelSubNode = null; | |
} | |
protected ModelTreeAction(ModelNode.ModelSubNode modelSubNode, Element actionElement) { | |
if (Debug.verboseOn()) | |
Debug.logVerbose("Reading Tree action with name: " + actionElement.getNodeName(), module); | |
this.modelSubNode = modelSubNode; | |
this.modelTree = modelSubNode.getNode().getModelTree(); | |
} | |
public ModelNode.ModelSubNode getModelSubNode() { | |
return modelSubNode; | |
} | |
public ModelTree getModelTree() { | |
return modelTree; | |
} | |
/** | |
* Models the <entity-and> element. | |
* | |
* @see <code>widget-tree.xsd</code> | |
*/ | |
public static class EntityAnd extends ModelTreeAction { | |
private final ByAndFinder finder; | |
private final String listName; | |
public EntityAnd(ModelNode.ModelSubNode modelSubNode, Element entityAndElement) { | |
super(modelSubNode, entityAndElement); | |
boolean useCache = "true".equalsIgnoreCase(entityAndElement.getAttribute("use-cache")); | |
Document ownerDoc = entityAndElement.getOwnerDocument(); | |
if (!useCache) | |
UtilXml.addChildElement(entityAndElement, "use-iterator", ownerDoc); | |
String listName = UtilFormatOut.checkEmpty(entityAndElement.getAttribute("list"), | |
entityAndElement.getAttribute("list-name")); | |
if (UtilValidate.isEmpty(listName)) | |
listName = "_LIST_ITERATOR_"; | |
this.listName = listName; | |
entityAndElement.setAttribute("list-name", this.listName); | |
finder = new ByAndFinder(entityAndElement); | |
} | |
@Override | |
public void accept(ModelActionVisitor visitor) throws Exception { | |
visitor.visit(this); | |
} | |
public ByAndFinder getFinder() { | |
return finder; | |
} | |
public String getListName() { | |
return listName; | |
} | |
@Override | |
public void runAction(Map<String, Object> context) { | |
try { | |
context.put(this.listName, null); | |
finder.runFind(context, WidgetWorker.getDelegator(context)); | |
Object obj = context.get(this.listName); | |
if (obj != null && (obj instanceof EntityListIterator || obj instanceof ListIterator<?>)) { | |
ListIterator<? extends Map<String, ? extends Object>> listIt = UtilGenerics.cast(obj); | |
this.getModelSubNode().setListIterator(listIt, context); | |
} else { | |
if (obj instanceof List<?>) { | |
List<? extends Map<String, ? extends Object>> list = UtilGenerics.checkList(obj); | |
this.getModelSubNode().setListIterator(list.listIterator(), 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-tree.xsd</code> | |
*/ | |
public static class EntityCondition extends ModelTreeAction { | |
private final ByConditionFinder finder; | |
private final String listName; | |
public EntityCondition(ModelNode.ModelSubNode modelSubNode, Element entityConditionElement) { | |
super(modelSubNode, entityConditionElement); | |
Document ownerDoc = entityConditionElement.getOwnerDocument(); | |
boolean useCache = "true".equalsIgnoreCase(entityConditionElement.getAttribute("use-cache")); | |
if (!useCache) | |
UtilXml.addChildElement(entityConditionElement, "use-iterator", ownerDoc); | |
String listName = UtilFormatOut.checkEmpty(entityConditionElement.getAttribute("list"), | |
entityConditionElement.getAttribute("list-name")); | |
if (UtilValidate.isEmpty(listName)) | |
listName = "_LIST_ITERATOR_"; | |
this.listName = listName; | |
entityConditionElement.setAttribute("list-name", this.listName); | |
finder = new ByConditionFinder(entityConditionElement); | |
} | |
@Override | |
public void accept(ModelActionVisitor visitor) throws Exception { | |
visitor.visit(this); | |
} | |
public ByConditionFinder getFinder() { | |
return finder; | |
} | |
public String getListName() { | |
return listName; | |
} | |
@Override | |
public void runAction(Map<String, Object> context) { | |
try { | |
context.put(this.listName, null); | |
finder.runFind(context, WidgetWorker.getDelegator(context)); | |
Object obj = context.get(this.listName); | |
if (obj != null && (obj instanceof EntityListIterator || obj instanceof ListIterator<?>)) { | |
ListIterator<? extends Map<String, ? extends Object>> listIt = UtilGenerics.cast(obj); | |
this.getModelSubNode().setListIterator(listIt, context); | |
} else { | |
if (obj instanceof List<?>) { | |
List<? extends Map<String, ? extends Object>> list = UtilGenerics.cast(obj); | |
this.getModelSubNode().setListIterator(list.listIterator(), 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 <script> element. | |
* | |
* @see <code>widget-tree.xsd</code> | |
*/ | |
public static class Script extends ModelTreeAction { | |
private final String location; | |
private final String method; | |
public Script(ModelNode modelNode, Element scriptElement) { | |
super(modelNode, scriptElement); | |
String scriptLocation = scriptElement.getAttribute("location"); | |
this.location = WidgetWorker.getScriptLocation(scriptLocation); | |
this.method = WidgetWorker.getScriptMethodName(scriptLocation); | |
} | |
public Script(ModelNode.ModelSubNode modelSubNode, Element scriptElement) { | |
super(modelSubNode, 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); | |
} | |
public String getLocation() { | |
return location; | |
} | |
public String getMethod() { | |
return method; | |
} | |
@Override | |
public void runAction(Map<String, Object> context) { | |
context.put("_LIST_ITERATOR_", null); | |
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 RuntimeException("Error running simple method at location [" + location + "]", e); | |
} | |
} else { | |
ScriptUtil.executeScript(this.location, this.method, context); | |
} | |
Object obj = context.get("_LIST_ITERATOR_"); | |
if (this.getModelSubNode() != null) { | |
if (obj != null && (obj instanceof EntityListIterator || obj instanceof ListIterator<?>)) { | |
ListIterator<? extends Map<String, ? extends Object>> listIt = UtilGenerics.cast(obj); | |
this.getModelSubNode().setListIterator(listIt, context); | |
} else { | |
if (obj instanceof List<?>) { | |
List<? extends Map<String, ? extends Object>> list = UtilGenerics.checkList(obj); | |
this.getModelSubNode().setListIterator(list.listIterator(), context); | |
} | |
} | |
} | |
} | |
} | |
/** | |
* Models the <service> element. | |
* | |
* @see <code>widget-tree.xsd</code> | |
*/ | |
public static class Service extends ModelTreeAction { | |
private final FlexibleStringExpander autoFieldMapExdr; | |
private final Map<FlexibleMapAccessor<Object>, Object> fieldMap; | |
private final FlexibleStringExpander resultMapListNameExdr; | |
private final FlexibleMapAccessor<Map<String, Object>> resultMapNameAcsr; | |
private final FlexibleStringExpander resultMapValueNameExdr; | |
private final FlexibleStringExpander serviceNameExdr; | |
private final FlexibleStringExpander valueNameExdr; | |
public Service(ModelNode modelNode, Element serviceElement) { | |
super(modelNode, 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.resultMapListNameExdr = FlexibleStringExpander.getInstance(serviceElement.getAttribute("result-map-list")); | |
this.resultMapValueNameExdr = FlexibleStringExpander.getInstance(serviceElement.getAttribute("result-map-value")); | |
this.valueNameExdr = FlexibleStringExpander.getInstance(serviceElement.getAttribute("value")); | |
this.fieldMap = EntityFinderUtil.makeFieldMap(serviceElement); | |
} | |
public Service(ModelNode.ModelSubNode modelSubNode, Element serviceElement) { | |
super(modelSubNode, 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.resultMapListNameExdr = FlexibleStringExpander.getInstance(serviceElement.getAttribute("result-map-list")); | |
this.resultMapValueNameExdr = FlexibleStringExpander.getInstance(serviceElement.getAttribute("result-map-value")); | |
this.valueNameExdr = FlexibleStringExpander.getInstance(serviceElement.getAttribute("value")); | |
this.fieldMap = EntityFinderUtil.makeFieldMap(serviceElement); | |
} | |
@Override | |
public void accept(ModelActionVisitor visitor) throws Exception { | |
visitor.visit(this); | |
} | |
public FlexibleStringExpander getAutoFieldMapExdr() { | |
return autoFieldMapExdr; | |
} | |
public Map<FlexibleMapAccessor<Object>, Object> getFieldMap() { | |
return fieldMap; | |
} | |
public FlexibleStringExpander getResultMapListNameExdr() { | |
return resultMapListNameExdr; | |
} | |
public FlexibleMapAccessor<Map<String, Object>> getResultMapNameAcsr() { | |
return resultMapNameAcsr; | |
} | |
public FlexibleStringExpander getResultMapValueNameExdr() { | |
return resultMapValueNameExdr; | |
} | |
public FlexibleStringExpander getServiceNameExdr() { | |
return serviceNameExdr; | |
} | |
public FlexibleStringExpander getValueNameExdr() { | |
return valueNameExdr; | |
} | |
@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); | |
boolean autoFieldMapBool = !"false".equals(autoFieldMapString); | |
try { | |
Map<String, Object> serviceContext = null; | |
if (autoFieldMapBool) { | |
serviceContext = WidgetWorker.getDispatcher(context).getDispatchContext() | |
.makeValidContext(serviceNameExpanded, ModelService.IN_PARAM, context); | |
} else { | |
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); | |
} | |
String resultMapListName = resultMapListNameExdr.expandString(context); | |
//String resultMapListIteratorName = resultMapListIteratorNameExdr.expandString(context); | |
String resultMapValueName = resultMapValueNameExdr.expandString(context); | |
String valueName = valueNameExdr.expandString(context); | |
if (this.getModelSubNode() != null) { | |
//ListIterator iter = null; | |
if (UtilValidate.isNotEmpty(resultMapListName)) { | |
List<? extends Map<String, ? extends Object>> lst = UtilGenerics.checkList(result.get(resultMapListName)); | |
if (lst != null) { | |
if (lst instanceof ListIterator<?>) { | |
ListIterator<? extends Map<String, ? extends Object>> listIt = UtilGenerics.cast(lst); | |
this.getModelSubNode().setListIterator(listIt, context); | |
} else { | |
this.getModelSubNode().setListIterator(lst.listIterator(), context); | |
} | |
} | |
} | |
} else { | |
if (UtilValidate.isNotEmpty(resultMapValueName)) { | |
if (UtilValidate.isNotEmpty(valueName)) { | |
context.put(valueName, result.get(resultMapValueName)); | |
} else { | |
Map<String, Object> resultMap = UtilGenerics.checkMap(result.get(resultMapValueName)); | |
context.putAll(resultMap); | |
} | |
} | |
} | |
} catch (GenericServiceException e) { | |
String errMsg = "Error calling service with name " + serviceNameExpanded + ": " + e.toString(); | |
Debug.logError(e, errMsg, module); | |
throw new IllegalArgumentException(errMsg); | |
} | |
} | |
} | |
} |