Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelTree.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelTree.java?rev=1652852&view=auto ============================================================================== --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelTree.java (added) +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelTree.java Sun Jan 18 21:03:40 2015 @@ -0,0 +1,1135 @@ +/******************************************************************************* + * 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.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.xml.parsers.ParserConfigurationException; + +import org.ofbiz.base.util.Debug; +import org.ofbiz.base.util.GeneralException; +import org.ofbiz.base.util.StringUtil; +import org.ofbiz.base.util.UtilCodec; +import org.ofbiz.base.util.UtilGenerics; +import org.ofbiz.base.util.UtilHttp; +import org.ofbiz.base.util.UtilValidate; +import org.ofbiz.base.util.UtilXml; +import org.ofbiz.base.util.collections.MapStack; +import org.ofbiz.base.util.string.FlexibleStringExpander; +import org.ofbiz.entity.Delegator; +import org.ofbiz.entity.GenericEntityException; +import org.ofbiz.entity.GenericValue; +import org.ofbiz.entity.model.ModelEntity; +import org.ofbiz.entity.model.ModelField; +import org.ofbiz.entity.util.EntityListIterator; +import org.ofbiz.entity.util.EntityQuery; +import org.ofbiz.widget.WidgetWorker; +import org.ofbiz.widget.model.CommonWidgetModels.Parameter; +import org.ofbiz.widget.renderer.ScreenRenderException; +import org.ofbiz.widget.renderer.ScreenStringRenderer; +import org.ofbiz.widget.renderer.TreeStringRenderer; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +/** + * Models the <tree> element. + * + * @see <code>widget-tree.xsd</code> + */ +@SuppressWarnings("serial") +public class ModelTree extends ModelWidget { + + /* + * ----------------------------------------------------------------------- * + * 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 = ModelTree.class.getName(); + + private final String defaultEntityName; + private final String defaultRenderStyle; + private final FlexibleStringExpander defaultWrapStyleExdr; + private final FlexibleStringExpander expandCollapseRequestExdr; + private final boolean forceChildCheck; + private final String location; + private final Map<String, ModelNode> nodeMap; + private final int openDepth; + private final int postTrailOpenDepth; + private final String rootNodeName; + private final FlexibleStringExpander trailNameExdr; + + public ModelTree(Element treeElement, String location) { + super(treeElement); + this.location = location; + this.rootNodeName = treeElement.getAttribute("root-node-name"); + String defaultRenderStyle = UtilXml.checkEmpty(treeElement.getAttribute("default-render-style"), "simple"); + // A temporary hack to accommodate those who might still be using "render-style" instead of "default-render-style" + if (defaultRenderStyle.isEmpty() || defaultRenderStyle.equals("simple")) { + String rStyle = treeElement.getAttribute("render-style"); + if (!rStyle.isEmpty()) + defaultRenderStyle = rStyle; + } + this.defaultRenderStyle = defaultRenderStyle; + this.defaultWrapStyleExdr = FlexibleStringExpander.getInstance(treeElement.getAttribute("default-wrap-style")); + this.expandCollapseRequestExdr = FlexibleStringExpander.getInstance(treeElement.getAttribute("expand-collapse-request")); + this.trailNameExdr = FlexibleStringExpander.getInstance(UtilXml.checkEmpty(treeElement.getAttribute("trail-name"), + "trail")); + this.forceChildCheck = !"false".equals(treeElement.getAttribute("force-child-check")); + this.defaultEntityName = treeElement.getAttribute("entity-name"); + int openDepth = 0; + if (treeElement.hasAttribute("open-depth")) { + try { + openDepth = Integer.parseInt(treeElement.getAttribute("open-depth")); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid open-depth attribute value for the tree definition with name: " + + getName()); + } + } + this.openDepth = openDepth; + int postTrailOpenDepth = 999; + if (treeElement.hasAttribute("post-trail-open-depth")) { + try { + postTrailOpenDepth = Integer.parseInt(treeElement.getAttribute("post-trail-open-depth")); + } catch (NumberFormatException e) { + throw new IllegalArgumentException( + "Invalid post-trail-open-depth attribute value for the tree definition with name: " + getName()); + } + } + this.postTrailOpenDepth = postTrailOpenDepth; + List<? extends Element> nodeElements = UtilXml.childElementList(treeElement, "node"); + if (nodeElements.size() == 0) { + throw new IllegalArgumentException("No node elements found for the tree definition with name: " + getName()); + } + Map<String, ModelNode> nodeMap = new HashMap<String, ModelNode>(); + for (Element nodeElementEntry : UtilXml.childElementList(treeElement, "node")) { + ModelNode node = new ModelNode(nodeElementEntry, this); + String nodeName = node.getName(); + nodeMap.put(nodeName, node); + } + this.nodeMap = Collections.unmodifiableMap(nodeMap); + } + + @Override + public void accept(ModelWidgetVisitor visitor) throws Exception { + visitor.visit(this); + } + + @Override + public String getBoundaryCommentName() { + return location + "#" + getName(); + } + + public String getDefaultEntityName() { + return this.defaultEntityName; + } + + public String getDefaultPkName(Map<String, Object> context) { + ModelEntity modelEntity = WidgetWorker.getDelegator(context).getModelEntity(this.defaultEntityName); + if (modelEntity.getPksSize() == 1) { + ModelField modelField = modelEntity.getOnlyPk(); + return modelField.getName(); + } + return null; + } + + public String getExpandCollapseRequest(Map<String, Object> context) { + String expColReq = this.expandCollapseRequestExdr.expandString(context); + if (UtilValidate.isEmpty(expColReq)) { + HttpServletRequest request = (HttpServletRequest) context.get("request"); + String s1 = request.getRequestURI(); + int pos = s1.lastIndexOf("/"); + if (pos >= 0) + expColReq = s1.substring(pos + 1); + else + expColReq = s1; + } + //append also the request parameters + Map<String, Object> paramMap = UtilGenerics.checkMap(context.get("requestParameters")); + if (UtilValidate.isNotEmpty(paramMap)) { + Map<String, Object> requestParameters = new HashMap<String, Object>(paramMap); + requestParameters.remove(this.getTrailName(context)); + if (UtilValidate.isNotEmpty(requestParameters)) { + String queryString = UtilHttp.urlEncodeArgs(requestParameters, false); + if (expColReq.indexOf("?") < 0) { + expColReq += "?"; + } else { + expColReq += "&"; + } + expColReq += queryString; + } + } + return expColReq; + } + + public int getOpenDepth() { + return openDepth; + } + + public int getPostTrailOpenDepth() { + return postTrailOpenDepth; + } + + public String getRenderStyle() { + return this.defaultRenderStyle; + } + + public String getRootNodeName() { + return rootNodeName; + } + + public String getTrailName(Map<String, Object> context) { + return this.trailNameExdr.expandString(context); + } + + public String getWrapStyle(Map<String, Object> context) { + return this.defaultWrapStyleExdr.expandString(context); + } + + /** + * Renders this model. + * + * @param writer + * @param context + * @param treeStringRenderer + */ + @SuppressWarnings("rawtypes") + public void renderTreeString(Appendable writer, Map<String, Object> context, TreeStringRenderer treeStringRenderer) + throws GeneralException { + Map<String, Object> parameters = UtilGenerics.checkMap(context.get("parameters")); + ModelNode node = nodeMap.get(rootNodeName); + String trailName = trailNameExdr.expandString(context); + String treeString = (String) context.get(trailName); + if (UtilValidate.isEmpty(treeString)) { + treeString = (String) parameters.get(trailName); + } + List<String> trail = null; + if (UtilValidate.isNotEmpty(treeString)) { + trail = StringUtil.split(treeString, "|"); + if (UtilValidate.isEmpty(trail)) + throw new RuntimeException("Tree 'trail' value is empty."); + context.put("rootEntityId", trail.get(0)); + context.put(getDefaultPkName(context), trail.get(0)); + } else { + trail = new LinkedList<String>(); + } + context.put("targetNodeTrail", trail); + context.put("currentNodeTrail", new LinkedList()); + try { + node.renderNodeString(writer, context, treeStringRenderer, 0); + } catch (IOException e2) { + String errMsg = "Error rendering included label with name [" + getName() + "] : " + e2.toString(); + Debug.logError(e2, errMsg, module); + throw new RuntimeException(errMsg); + } + + } + + public String getDefaultRenderStyle() { + return defaultRenderStyle; + } + + public FlexibleStringExpander getDefaultWrapStyleExdr() { + return defaultWrapStyleExdr; + } + + public FlexibleStringExpander getExpandCollapseRequestExdr() { + return expandCollapseRequestExdr; + } + + public boolean getForceChildCheck() { + return forceChildCheck; + } + + public String getLocation() { + return location; + } + + public Map<String, ModelNode> getNodeMap() { + return nodeMap; + } + + public FlexibleStringExpander getTrailNameExdr() { + return trailNameExdr; + } + + /** + * Models the <node> element. + * + * @see <code>widget-tree.xsd</code> + */ + public static class ModelNode extends ModelWidget { + + private final List<ModelAction> actions; + // TODO: Make this a generic condition object. + private final ModelTreeCondition condition; + private final String entityName; + private final String entryName; + private final String expandCollapseStyle; + private final Label label; + private final Link link; + private final ModelTree modelTree; + private final String pkName; + private final String renderStyle; + private final FlexibleStringExpander screenLocationExdr; + private final FlexibleStringExpander screenNameExdr; + private final String shareScope; + private final List<ModelSubNode> subNodeList; + private final FlexibleStringExpander wrapStyleExdr; + + public ModelNode(Element nodeElement, ModelTree modelTree) { + super(nodeElement); + this.modelTree = modelTree; + this.expandCollapseStyle = nodeElement.getAttribute("expand-collapse-style"); + this.wrapStyleExdr = FlexibleStringExpander.getInstance(nodeElement.getAttribute("wrap-style")); + this.renderStyle = nodeElement.getAttribute("render-style"); + this.entryName = nodeElement.getAttribute("entry-name"); + this.entityName = nodeElement.getAttribute("entity-name"); + this.pkName = nodeElement.getAttribute("join-field-name"); + ArrayList<ModelAction> actions = new ArrayList<ModelAction>(); + // FIXME: Validate child elements, should be only one of actions, entity-one, service, script. + Element actionsElement = UtilXml.firstChildElement(nodeElement, "actions"); + if (actionsElement != null) { + actions.addAll(ModelTreeAction.readNodeActions(this, actionsElement)); + } + Element actionElement = UtilXml.firstChildElement(nodeElement, "entity-one"); + if (actionElement != null) { + actions.add(new AbstractModelAction.EntityOne(this, actionElement)); + } + actionElement = UtilXml.firstChildElement(nodeElement, "service"); + if (actionElement != null) { + actions.add(new ModelTreeAction.Service(this, actionElement)); + } + actionElement = UtilXml.firstChildElement(nodeElement, "script"); + if (actionElement != null) { + actions.add(new ModelTreeAction.Script(this, actionElement)); + } + actions.trimToSize(); + this.actions = Collections.unmodifiableList(actions); + Element screenElement = UtilXml.firstChildElement(nodeElement, "include-screen"); + if (screenElement != null) { + this.screenNameExdr = FlexibleStringExpander.getInstance(screenElement.getAttribute("name")); + this.screenLocationExdr = FlexibleStringExpander.getInstance(screenElement.getAttribute("location")); + this.shareScope = screenElement.getAttribute("share-scope"); + } else { + this.screenNameExdr = FlexibleStringExpander.getInstance(""); + this.screenLocationExdr = FlexibleStringExpander.getInstance(""); + this.shareScope = ""; + } + Element labelElement = UtilXml.firstChildElement(nodeElement, "label"); + if (labelElement != null) { + this.label = new Label(labelElement); + } else { + this.label = null; + } + Element linkElement = UtilXml.firstChildElement(nodeElement, "link"); + if (linkElement != null) { + this.link = new Link(linkElement); + } else { + this.link = null; + } + Element conditionElement = UtilXml.firstChildElement(nodeElement, "condition"); + if (conditionElement != null) { + this.condition = new ModelTreeCondition(modelTree, conditionElement); + } else { + this.condition = null; + } + List<? extends Element> nodeElements = UtilXml.childElementList(nodeElement, "sub-node"); + if (!nodeElements.isEmpty()) { + List<ModelSubNode> subNodeList = new ArrayList<ModelSubNode>(); + for (Element subNodeElementEntry : nodeElements) { + ModelSubNode subNode = new ModelSubNode(subNodeElementEntry, this); + subNodeList.add(subNode); + } + this.subNodeList = Collections.unmodifiableList(subNodeList); + } else { + this.subNodeList = Collections.emptyList(); + } + } + + @Override + public void accept(ModelWidgetVisitor visitor) throws Exception { + visitor.visit(this); + } + + private List<Object[]> getChildren(Map<String, Object> context) { + List<Object[]> subNodeValues = new ArrayList<Object[]>(); + for (ModelSubNode subNode : subNodeList) { + String nodeName = subNode.getNodeName(context); + ModelNode node = modelTree.nodeMap.get(nodeName); + List<ModelAction> subNodeActions = subNode.getActions(); + //if (Debug.infoOn()) Debug.logInfo(" context.currentValue:" + context.get("currentValue"), module); + AbstractModelAction.runSubActions(subNodeActions, context); + // List dataFound = (List)context.get("dataFound"); + Iterator<? extends Map<String, ? extends Object>> dataIter = subNode.getListIterator(context); + if (dataIter instanceof EntityListIterator) { + EntityListIterator eli = (EntityListIterator) dataIter; + Map<String, Object> val = null; + while ((val = eli.next()) != null) { + Object[] arr = { node, val }; + subNodeValues.add(arr); + } + try { + eli.close(); + } catch (GenericEntityException e) { + Debug.logError(e, module); + throw new RuntimeException(e.getMessage()); + } + } else if (dataIter != null) { + while (dataIter.hasNext()) { + Map<String, ? extends Object> val = dataIter.next(); + Object[] arr = { node, val }; + subNodeValues.add(arr); + } + } + } + return subNodeValues; + } + + public String getEntityName() { + if (!this.entityName.isEmpty()) { + return this.entityName; + } else { + return this.modelTree.getDefaultEntityName(); + } + } + + public String getEntryName() { + return this.entryName; + } + + public String getExpandCollapseStyle() { + return expandCollapseStyle; + } + + public ModelTree getModelTree() { + return this.modelTree; + } + + public String getPkName(Map<String, Object> context) { + if (UtilValidate.isNotEmpty(this.pkName)) { + return this.pkName; + } else { + return this.modelTree.getDefaultPkName(context); + } + } + + public String getRenderStyle() { + if (this.renderStyle.isEmpty()) + return modelTree.getRenderStyle(); + return this.renderStyle; + } + + public String getWrapStyle(Map<String, Object> context) { + String val = this.wrapStyleExdr.expandString(context); + if (val.isEmpty()) { + val = this.modelTree.getWrapStyle(context); + } + return val; + } + + public boolean hasChildren(Map<String, Object> context) { + List<Object[]> subNodeValues = getChildren(context); + boolean hasChildren = false; + Long nodeCount = null; + String countFieldName = "childBranchCount"; + Object obj = null; + if (!this.entryName.isEmpty()) { + Map<String, Object> map = UtilGenerics.cast(context.get(this.entryName)); + if (map instanceof GenericValue) { + ModelEntity modelEntity = ((GenericValue) map).getModelEntity(); + if (modelEntity.isField(countFieldName)) { + obj = map.get(countFieldName); + } + } + } else { + obj = context.get(countFieldName); + } + if (obj != null) { + nodeCount = (Long) obj; + } + String entName = this.getEntityName(); + Delegator delegator = WidgetWorker.getDelegator(context); + ModelEntity modelEntity = delegator.getModelEntity(entName); + ModelField modelField = null; + if (modelEntity.isField(countFieldName)) { + modelField = modelEntity.getField(countFieldName); + } + if (nodeCount == null && modelField != null || this.modelTree.forceChildCheck) { + getChildren(context); + /* + String id = (String)context.get(modelTree.getPkName()); + if (UtilValidate.isNotEmpty(id)) { + try { + int leafCount = ContentManagementWorker.updateStatsTopDown(delegator, id, UtilMisc.toList("SUB_CONTENT", "PUBLISH_LINK")); + GenericValue entity = delegator.findOne(entName, UtilMisc.toMap(modelTree.getPkName(), id), true); + obj = entity.get("childBranchCount"); + if (obj != null) + nodeCount = (Long)obj; + } catch (GenericEntityException e) { + Debug.logError(e, module); + throw new RuntimeException(e.getMessage()); + } + } + */ + nodeCount = Long.valueOf(subNodeValues.size()); + String pkName = this.getPkName(context); + String id = null; + if (!this.entryName.isEmpty()) { + id = UtilGenerics.<Map<String, String>> cast(context.get(this.entryName)).get(pkName); + } else { + id = (String) context.get(pkName); + } + try { + if (id != null && modelEntity.getPksSize() == 1) { + GenericValue entity = EntityQuery.use(delegator).from(entName).where(pkName, id).queryOne(); + if (modelEntity.isField("childBranchCount")) { + entity.put("childBranchCount", nodeCount); + entity.store(); + } + } + } catch (GenericEntityException e) { + Debug.logError(e, module); + throw new RuntimeException(e.getMessage()); + } + } else if (nodeCount == null) { + getChildren(context); + if (subNodeValues != null) { + nodeCount = Long.valueOf(subNodeValues.size()); + } + } + if (nodeCount != null && nodeCount.intValue() > 0) { + hasChildren = true; + } + return hasChildren; + } + + public boolean isExpandCollapse() { + boolean isExpCollapse = false; + String rStyle = getRenderStyle(); + if (rStyle != null && rStyle.equals("expand-collapse")) + isExpCollapse = true; + return isExpCollapse; + } + + public boolean isFollowTrail() { + boolean isFollowTrail = false; + String rStyle = getRenderStyle(); + if (rStyle != null && (rStyle.equals("follow-trail") || rStyle.equals("show-peers") || rStyle.equals("follow-trail"))) { + isFollowTrail = true; + } + return isFollowTrail; + } + + public boolean isRootNode() { + return getName().equals(modelTree.getRootNodeName()); + } + + public void renderNodeString(Appendable writer, Map<String, Object> context, TreeStringRenderer treeStringRenderer, + int depth) throws IOException, GeneralException { + boolean passed = true; + if (this.condition != null) { + if (!this.condition.getCondition().eval(context)) { + passed = false; + } + } + //Debug.logInfo("in ModelMenu, name:" + this.getName(), module); + if (passed) { + List<String> currentNodeTrail = UtilGenerics.toList(context.get("currentNodeTrail")); + context.put("processChildren", Boolean.TRUE); + // this action will usually obtain the "current" entity + ModelTreeAction.runSubActions(this.actions, context); + String pkName = getPkName(context); + String id = null; + if (!this.entryName.isEmpty()) { + id = UtilGenerics.<Map<String, String>> cast(context.get(this.entryName)).get(pkName); + } else { + id = (String) context.get(pkName); + } + currentNodeTrail.add(id); + treeStringRenderer.renderNodeBegin(writer, context, this, depth); + //if (Debug.infoOn()) Debug.logInfo(" context:" + + // context.entrySet(), module); + try { + String screenName = null; + if (!screenNameExdr.isEmpty()) + screenName = screenNameExdr.expandString(context); + String screenLocation = null; + if (!screenLocationExdr.isEmpty()) + screenLocation = screenLocationExdr.expandString(context); + if (screenName != null && screenLocation != null) { + ScreenStringRenderer screenStringRenderer = treeStringRenderer.getScreenStringRenderer(context); + ModelScreen modelScreen = ScreenFactory.getScreenFromLocation(screenLocation, screenName); + modelScreen.renderScreenString(writer, context, screenStringRenderer); + } + if (label != null) { + label.renderLabelString(writer, context, treeStringRenderer); + } + if (link != null) { + link.renderLinkString(writer, context, treeStringRenderer); + } + treeStringRenderer.renderLastElement(writer, context, this); + Boolean processChildren = (Boolean) context.get("processChildren"); + //if (Debug.infoOn()) Debug.logInfo(" processChildren:" + processChildren, module); + if (processChildren.booleanValue()) { + List<Object[]> subNodeValues = getChildren(context); + int newDepth = depth + 1; + for (Object[] arr : subNodeValues) { + ModelNode node = (ModelNode) arr[0]; + Map<String, Object> val = UtilGenerics.checkMap(arr[1]); + //GenericPK pk = val.getPrimaryKey(); + //if (Debug.infoOn()) Debug.logInfo(" pk:" + pk, + // module); + String thisPkName = node.getPkName(context); + String thisEntityId = (String) val.get(thisPkName); + MapStack<String> newContext = MapStack.create(context); + newContext.push(); + String nodeEntryName = node.getEntryName(); + if (!nodeEntryName.isEmpty()) { + newContext.put(nodeEntryName, val); + } else { + newContext.putAll(val); + } + String targetEntityId = null; + List<String> targetNodeTrail = UtilGenerics.checkList(context.get("targetNodeTrail")); + if (newDepth < targetNodeTrail.size()) { + targetEntityId = targetNodeTrail.get(newDepth); + } + if ((targetEntityId != null && targetEntityId.equals(thisEntityId)) + || this.showPeers(newDepth, context)) { + node.renderNodeString(writer, newContext, treeStringRenderer, newDepth); + } + } + } + } catch (ScreenRenderException e) { + String errMsg = "Error rendering included label with name [" + getName() + "] : " + e.toString(); + Debug.logError(e, errMsg, module); + throw new RuntimeException(errMsg); + } catch (SAXException e) { + String errMsg = "Error rendering included label with name [" + getName() + "] : " + e.toString(); + Debug.logError(e, errMsg, module); + throw new RuntimeException(errMsg); + } catch (ParserConfigurationException e3) { + String errMsg = "Error rendering included label with name [" + getName() + "] : " + e3.toString(); + Debug.logError(e3, errMsg, module); + throw new RuntimeException(errMsg); + } catch (IOException e2) { + String errMsg = "Error rendering included label with name [" + getName() + "] : " + e2.toString(); + Debug.logError(e2, errMsg, module); + throw new RuntimeException(errMsg); + } + treeStringRenderer.renderNodeEnd(writer, context, this); + int removeIdx = currentNodeTrail.size() - 1; + if (removeIdx >= 0) + currentNodeTrail.remove(removeIdx); + } + } + + public boolean showPeers(int currentDepth, Map<String, Object> context) { + int trailSize = 0; + List<?> trail = UtilGenerics.checkList(context.get("targetNodeTrail")); + int openDepth = modelTree.getOpenDepth(); + int postTrailOpenDepth = modelTree.getPostTrailOpenDepth(); + if (trail != null) + trailSize = trail.size(); + + boolean showPeers = false; + String rStyle = getRenderStyle(); + if (rStyle == null) { + showPeers = true; + } else if (!isFollowTrail()) { + showPeers = true; + } else if ((currentDepth < trailSize) && (rStyle != null) + && (rStyle.equals("show-peers") || rStyle.equals("expand-collapse"))) { + showPeers = true; + } else if (openDepth >= currentDepth) { + showPeers = true; + } else { + int depthAfterTrail = currentDepth - trailSize; + if (depthAfterTrail >= 0 && depthAfterTrail <= postTrailOpenDepth) + showPeers = true; + } + return showPeers; + } + + public List<ModelAction> getActions() { + return actions; + } + + public ModelTreeCondition getCondition() { + return condition; + } + + public Label getLabel() { + return label; + } + + public Link getLink() { + return link; + } + + public String getPkName() { + return pkName; + } + + public FlexibleStringExpander getScreenLocationExdr() { + return screenLocationExdr; + } + + public FlexibleStringExpander getScreenNameExdr() { + return screenNameExdr; + } + + public String getShareScope() { + return shareScope; + } + + public List<ModelSubNode> getSubNodeList() { + return subNodeList; + } + + public FlexibleStringExpander getWrapStyleExdr() { + return wrapStyleExdr; + } + + /** + * Models the <image> element. + * + * @see <code>widget-tree.xsd</code> + */ + public static class Image { + + private final FlexibleStringExpander borderExdr; + private final FlexibleStringExpander heightExdr; + private final FlexibleStringExpander idExdr; + private final FlexibleStringExpander srcExdr; + private final FlexibleStringExpander styleExdr; + private final String urlMode; + private final FlexibleStringExpander widthExdr; + + public Image(Element imageElement) { + this.borderExdr = FlexibleStringExpander + .getInstance(UtilXml.checkEmpty(imageElement.getAttribute("border"), "0")); + this.heightExdr = FlexibleStringExpander.getInstance(imageElement.getAttribute("height")); + this.idExdr = FlexibleStringExpander.getInstance(imageElement.getAttribute("id")); + this.srcExdr = FlexibleStringExpander.getInstance(imageElement.getAttribute("src")); + this.styleExdr = FlexibleStringExpander.getInstance(imageElement.getAttribute("style")); + this.urlMode = UtilXml.checkEmpty(imageElement.getAttribute("url-mode"), "content"); + this.widthExdr = FlexibleStringExpander.getInstance(imageElement.getAttribute("width")); + } + + public String getBorder(Map<String, Object> context) { + return this.borderExdr.expandString(context); + } + + public String getHeight(Map<String, Object> context) { + return this.heightExdr.expandString(context); + } + + public String getId(Map<String, Object> context) { + return this.idExdr.expandString(context); + } + + public String getSrc(Map<String, Object> context) { + return this.srcExdr.expandString(context); + } + + public String getStyle(Map<String, Object> context) { + return this.styleExdr.expandString(context); + } + + public String getUrlMode() { + return this.urlMode; + } + + public String getWidth(Map<String, Object> context) { + return this.widthExdr.expandString(context); + } + + public void renderImageString(Appendable writer, Map<String, Object> context, TreeStringRenderer treeStringRenderer) { + try { + treeStringRenderer.renderImage(writer, context, this); + } catch (IOException e) { + String errMsg = "Error rendering image with id [" + getId(context) + "]: " + e.toString(); + Debug.logError(e, errMsg, module); + throw new RuntimeException(errMsg); + } + } + } + + /** + * Models the <label> element. + * + * @see <code>widget-tree.xsd</code> + */ + public static final class Label { + private final FlexibleStringExpander idExdr; + private final FlexibleStringExpander styleExdr; + private final FlexibleStringExpander textExdr; + + public Label(Element labelElement) { + String textAttr = labelElement.getAttribute("text"); + String pcdata = UtilXml.checkEmpty(UtilXml.elementValue(labelElement), ""); + this.textExdr = FlexibleStringExpander.getInstance(textAttr + pcdata); + this.idExdr = FlexibleStringExpander.getInstance(labelElement.getAttribute("id")); + this.styleExdr = FlexibleStringExpander.getInstance(labelElement.getAttribute("style")); + } + + public String getId(Map<String, Object> context) { + return this.idExdr.expandString(context); + } + + public String getStyle(Map<String, Object> context) { + return this.styleExdr.expandString(context); + } + + public String getText(Map<String, Object> context) { + String text = this.textExdr.expandString(context); + // FIXME: Encoding should be done by the renderer, not by the model. + UtilCodec.SimpleEncoder simpleEncoder = (UtilCodec.SimpleEncoder) context.get("simpleEncoder"); + if (simpleEncoder != null) { + text = simpleEncoder.encode(text); + } + return text; + } + + public void renderLabelString(Appendable writer, Map<String, Object> context, TreeStringRenderer treeStringRenderer) { + try { + treeStringRenderer.renderLabel(writer, context, this); + } catch (IOException e) { + String errMsg = "Error rendering label with id [" + getId(context) + "]: " + e.toString(); + Debug.logError(e, errMsg, module); + throw new RuntimeException(errMsg); + } + } + + public FlexibleStringExpander getIdExdr() { + return idExdr; + } + + public FlexibleStringExpander getStyleExdr() { + return styleExdr; + } + + public FlexibleStringExpander getTextExdr() { + return textExdr; + } + } + + /** + * Models the <link> element. + * + * @see <code>widget-tree.xsd</code> + */ + public static class Link { + private final boolean encode; + private final boolean fullPath; + private final FlexibleStringExpander idExdr; + private final Image image; + private final String linkType; + private final FlexibleStringExpander nameExdr; + private final List<Parameter> parameterList; + private final FlexibleStringExpander prefixExdr; + private final boolean secure; + private final FlexibleStringExpander styleExdr; + private final FlexibleStringExpander targetExdr; + private final FlexibleStringExpander targetWindowExdr; + private final FlexibleStringExpander textExdr; + private final FlexibleStringExpander titleExdr; + private final String urlMode; + + public Link(Element linkElement) { + this.encode = "true".equals(linkElement.getAttribute("encode")); + this.fullPath = "true".equals(linkElement.getAttribute("full-path")); + this.idExdr = FlexibleStringExpander.getInstance(linkElement.getAttribute("id")); + Element imageElement = UtilXml.firstChildElement(linkElement, "image"); + if (imageElement != null) { + this.image = new Image(imageElement); + } else { + this.image = null; + } + this.linkType = linkElement.getAttribute("link-type"); + this.nameExdr = FlexibleStringExpander.getInstance(linkElement.getAttribute("name")); + List<? extends Element> parameterElementList = UtilXml.childElementList(linkElement, "parameter"); + if (!parameterElementList.isEmpty()) { + List<Parameter> parameterList = new ArrayList<Parameter>(parameterElementList.size()); + for (Element parameterElement : parameterElementList) { + parameterList.add(new Parameter(parameterElement)); + } + this.parameterList = Collections.unmodifiableList(parameterList); + } else { + this.parameterList = Collections.emptyList(); + } + this.prefixExdr = FlexibleStringExpander.getInstance(linkElement.getAttribute("prefix")); + this.secure = "true".equals(linkElement.getAttribute("secure")); + this.styleExdr = FlexibleStringExpander.getInstance(linkElement.getAttribute("style")); + this.targetExdr = FlexibleStringExpander.getInstance(linkElement.getAttribute("target")); + this.targetWindowExdr = FlexibleStringExpander.getInstance(linkElement.getAttribute("target-window")); + this.textExdr = FlexibleStringExpander.getInstance(linkElement.getAttribute("text")); + this.titleExdr = FlexibleStringExpander.getInstance(linkElement.getAttribute("title")); + this.urlMode = UtilXml.checkEmpty(linkElement.getAttribute("link-type"), "intra-app"); + } + + // FIXME: Using a widget model in this way is an ugly hack. + public Link(String style, String target, String text) { + this.encode = false; + this.fullPath = false; + this.idExdr = FlexibleStringExpander.getInstance(""); + this.image = null; + this.linkType = ""; + this.nameExdr = FlexibleStringExpander.getInstance(""); + this.parameterList = Collections.emptyList(); + this.prefixExdr = FlexibleStringExpander.getInstance(""); + this.secure = false; + this.styleExdr = FlexibleStringExpander.getInstance(style); + this.targetExdr = FlexibleStringExpander.getInstance(target); + this.targetWindowExdr = FlexibleStringExpander.getInstance(""); + this.textExdr = FlexibleStringExpander.getInstance(text); + this.titleExdr = FlexibleStringExpander.getInstance(""); + this.urlMode = "intra-app"; + } + + public boolean getEncode() { + return this.encode; + } + + public boolean getFullPath() { + return this.fullPath; + } + + public String getId(Map<String, Object> context) { + return this.idExdr.expandString(context); + } + + public Image getImage() { + return this.image; + } + + public String getLinkType() { + return this.linkType; + } + + public String getName(Map<String, Object> context) { + return this.nameExdr.expandString(context); + } + + public Map<String, String> getParameterMap(Map<String, Object> context) { + Map<String, String> fullParameterMap = new HashMap<String, String>(); + /* leaving this here... may want to add it at some point like the hyperlink element: + Map<String, String> addlParamMap = this.parametersMapAcsr.get(context); + if (addlParamMap != null) { + fullParameterMap.putAll(addlParamMap); + } + */ + for (CommonWidgetModels.Parameter parameter : this.parameterList) { + fullParameterMap.put(parameter.getName(), parameter.getValue(context)); + } + return fullParameterMap; + } + + public String getPrefix(Map<String, Object> context) { + return this.prefixExdr.expandString(context); + } + + public boolean getSecure() { + return this.secure; + } + + public String getStyle(Map<String, Object> context) { + return this.styleExdr.expandString(context); + } + + public String getTarget(Map<String, Object> context) { + UtilCodec.SimpleEncoder simpleEncoder = (UtilCodec.SimpleEncoder) context.get("simpleEncoder"); + if (simpleEncoder != null) { + return this.targetExdr.expandString(UtilCodec.HtmlEncodingMapWrapper.getHtmlEncodingMapWrapper(context, + simpleEncoder)); + } else { + return this.targetExdr.expandString(context); + } + } + + public String getTargetWindow(Map<String, Object> context) { + return this.targetWindowExdr.expandString(context); + } + + public String getText(Map<String, Object> context) { + String text = this.textExdr.expandString(context); + // FIXME: Encoding should be done by the renderer, not by the model. + UtilCodec.SimpleEncoder simpleEncoder = (UtilCodec.SimpleEncoder) context.get("simpleEncoder"); + if (simpleEncoder != null) { + text = simpleEncoder.encode(text); + } + return text; + } + + public String getTitle(Map<String, Object> context) { + String title = this.titleExdr.expandString(context); + // FIXME: Encoding should be done by the renderer, not by the model. + UtilCodec.SimpleEncoder simpleEncoder = (UtilCodec.SimpleEncoder) context.get("simpleEncoder"); + if (simpleEncoder != null) { + title = simpleEncoder.encode(title); + } + return title; + } + + public String getUrlMode() { + return this.urlMode; + } + + public void renderLinkString(Appendable writer, Map<String, Object> context, TreeStringRenderer treeStringRenderer) { + try { + treeStringRenderer.renderLink(writer, context, this); + } catch (IOException e) { + String errMsg = "Error rendering link with id [" + getId(context) + "]: " + e.toString(); + Debug.logError(e, errMsg, module); + throw new RuntimeException(errMsg); + } + } + + public FlexibleStringExpander getIdExdr() { + return idExdr; + } + + public FlexibleStringExpander getNameExdr() { + return nameExdr; + } + + public List<Parameter> getParameterList() { + return parameterList; + } + + public FlexibleStringExpander getPrefixExdr() { + return prefixExdr; + } + + public FlexibleStringExpander getStyleExdr() { + return styleExdr; + } + + public FlexibleStringExpander getTargetExdr() { + return targetExdr; + } + + public FlexibleStringExpander getTargetWindowExdr() { + return targetWindowExdr; + } + + public FlexibleStringExpander getTextExdr() { + return textExdr; + } + + public FlexibleStringExpander getTitleExdr() { + return titleExdr; + } + } + + /** + * Models the <sub-node> element. + * + * @see <code>widget-tree.xsd</code> + */ + public static class ModelSubNode extends ModelWidget { + + private final List<ModelAction> actions; + private final FlexibleStringExpander nodeNameExdr; + private final ModelNode rootNode; + private final String iteratorKey; + + public ModelSubNode(Element subNodeElement, ModelNode modelNode) { + super(subNodeElement); + this.rootNode = modelNode; + this.nodeNameExdr = FlexibleStringExpander.getInstance(subNodeElement.getAttribute("node-name")); + ArrayList<ModelAction> actions = new ArrayList<ModelAction>(); + // FIXME: Validate child elements, should be only one of actions, entity-and, entity-condition, service, script. + Element actionsElement = UtilXml.firstChildElement(subNodeElement, "actions"); + if (actionsElement != null) { + actions.addAll(ModelTreeAction.readSubNodeActions(this, actionsElement)); + } + Element actionElement = UtilXml.firstChildElement(subNodeElement, "entity-and"); + if (actionElement != null) { + actions.add(new ModelTreeAction.EntityAnd(this, actionElement)); + } + actionElement = UtilXml.firstChildElement(subNodeElement, "service"); + if (actionElement != null) { + actions.add(new ModelTreeAction.Service(this, actionElement)); + } + actionElement = UtilXml.firstChildElement(subNodeElement, "entity-condition"); + if (actionElement != null) { + actions.add(new ModelTreeAction.EntityCondition(this, actionElement)); + } + actionElement = UtilXml.firstChildElement(subNodeElement, "script"); + if (actionElement != null) { + actions.add(new ModelTreeAction.Script(this, actionElement)); + } + actions.trimToSize(); + this.actions = Collections.unmodifiableList(actions); + this.iteratorKey = this.rootNode.getName().concat(".").concat(this.nodeNameExdr.getOriginal()) + .concat(".ITERATOR"); + } + + @Override + public void accept(ModelWidgetVisitor visitor) throws Exception { + visitor.visit(this); + } + + public List<ModelAction> getActions() { + return actions; + } + + @SuppressWarnings("unchecked") + public ListIterator<? extends Map<String, ? extends Object>> getListIterator(Map<String, Object> context) { + return (ListIterator<? extends Map<String, ? extends Object>>) context.get(this.iteratorKey); + } + + public ModelTree.ModelNode getNode() { + return this.rootNode; + } + + public String getNodeName(Map<String, Object> context) { + return this.nodeNameExdr.expandString(context); + } + + public FlexibleStringExpander getNodeNameExdr() { + return nodeNameExdr; + } + + public void setListIterator(ListIterator<? extends Map<String, ? extends Object>> iter, Map<String, Object> context) { + context.put(this.iteratorKey, iter); + } + } + } +} Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelTreeAction.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelTreeAction.java?rev=1652852&view=auto ============================================================================== --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelTreeAction.java (added) +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelTreeAction.java Sun Jan 18 21:03:40 2015 @@ -0,0 +1,460 @@ +/******************************************************************************* + * 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); + } + } + } +} Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelTreeCondition.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelTreeCondition.java?rev=1652852&view=auto ============================================================================== --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelTreeCondition.java (added) +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelTreeCondition.java Sun Jan 18 21:03:40 2015 @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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 org.w3c.dom.Element; + +/** + * Models the <condition> element. + * + * @see <code>widget-tree.xsd</code> + */ +public class ModelTreeCondition { + public static final String module = ModelTreeCondition.class.getName(); + private final ModelCondition condition; + + public ModelTreeCondition(ModelTree modelTree, Element conditionElement) { + this.condition = AbstractModelCondition.DEFAULT_CONDITION_FACTORY.newInstance(modelTree, conditionElement); + } + + public ModelCondition getCondition() { + return condition; + } +} Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelWidget.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelWidget.java?rev=1652852&view=auto ============================================================================== --- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelWidget.java (added) +++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelWidget.java Sun Jan 18 21:03:40 2015 @@ -0,0 +1,154 @@ +/******************************************************************************* + * 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.io.Serializable; +import java.util.Map; + +import org.ofbiz.base.util.Debug; +import org.ofbiz.base.util.UtilGenerics; +import org.ofbiz.base.util.UtilProperties; +import org.w3c.dom.Element; + +/** + * Widget Library - Widget model class. ModelWidget is a base class that is + * extended by other widget model classes. + */ +@SuppressWarnings("serial") +public abstract class ModelWidget implements Serializable { + + public static final String module = ModelWidget.class.getName(); + /** + * The parameter name used to control widget boundary comments. Currently + * set to "widgetVerbose". + */ + public static final String enableBoundaryCommentsParam = "widgetVerbose"; + + private final String name; + private final String systemId; + private final int startColumn; + private final int startLine; + + /** + * Derived classes must call this constructor. + * @param name The widget name + */ + protected ModelWidget(String name) { + this.name = name; + this.systemId = "anonymous"; + this.startColumn = 0; + this.startLine = 0; + } + + /** + * Derived classes must call this constructor. + * @param widgetElement The XML Element for the widget + */ + protected ModelWidget(Element widgetElement) { + this.name = widgetElement.getAttribute("name"); + this.systemId = (String) widgetElement.getUserData("systemId"); + this.startColumn = ((Integer) widgetElement.getUserData("startColumn")).intValue(); + this.startLine = ((Integer) widgetElement.getUserData("startLine")).intValue(); + } + + public abstract void accept(ModelWidgetVisitor visitor) throws Exception; + + /** + * Returns the widget's name. + * @return Widget's name + */ + public String getName() { + return name; + } + + /** + * Returns the url as a string, from where this widget was defined. + * @return url + */ + public String getSystemId() { + return systemId; + } + + /** + * Returns the column where this widget was defined, in it's containing xml file. + * @return start column + */ + public int getStartColumn() { + return startColumn; + } + + /** + * Returns the line where this widget was defined, in it's containing xml file. + * @return start line + */ + public int getStartLine() { + return startLine; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + ModelWidgetVisitor visitor = new XmlWidgetVisitor(sb); + try { + accept(visitor); + } catch (Exception e) { + Debug.logWarning(e, "Exception thrown in XmlWidgetVisitor: ", module); + } + return sb.toString(); + } + + /** + * Returns the widget's name to be used in boundary comments. The default action + * is to return the widget's name. Derived classes can override this method to + * return a customized name. + * @return Name to be used in boundary comments + */ + public String getBoundaryCommentName() { + return name; + } + + /** + * Returns <code>true</code> if widget boundary comments are enabled. Widget boundary comments are + * enabled by setting <code>widget.verbose=true</code> in the <code>widget.properties</code> file. + * The <code>true</code> setting can be overridden in <code>web.xml</code> or in the screen + * rendering context. If <code>widget.verbose</code> is set to <code>false</code> in the + * <code>widget.properties</code> file, then that setting will override all other settings and + * disable all widget boundary comments. + * + * @param context Optional context Map + */ + public static boolean widgetBoundaryCommentsEnabled(Map<String, ? extends Object> context) { + boolean result = "true".equals(UtilProperties.getPropertyValue("widget", "widget.verbose")); + if (result && context != null) { + String str = (String) context.get(enableBoundaryCommentsParam); + if (str != null) { + result = "true".equals(str); + } else{ + Map<String, ? extends Object> parameters = UtilGenerics.checkMap(context.get("parameters")); + if (parameters != null) { + str = (String) parameters.get(enableBoundaryCommentsParam); + if (str != null) { + result = "true".equals(str); + } + } + } + } + return result; + } +} |
Free forum by Nabble | Edit this page |