blob: 2c3f927f6b631dab3092df532614704c303471af [file] [log] [blame]
/*******************************************************************************
* 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.apache.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.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.GeneralException;
import org.apache.ofbiz.base.util.StringUtil;
import org.apache.ofbiz.base.util.UtilCodec;
import org.apache.ofbiz.base.util.UtilGenerics;
import org.apache.ofbiz.base.util.UtilHttp;
import org.apache.ofbiz.base.util.UtilValidate;
import org.apache.ofbiz.base.util.UtilXml;
import org.apache.ofbiz.base.util.collections.MapStack;
import org.apache.ofbiz.base.util.string.FlexibleStringExpander;
import org.apache.ofbiz.entity.Delegator;
import org.apache.ofbiz.entity.GenericEntityException;
import org.apache.ofbiz.entity.GenericValue;
import org.apache.ofbiz.entity.model.ModelEntity;
import org.apache.ofbiz.entity.model.ModelField;
import org.apache.ofbiz.entity.util.EntityListIterator;
import org.apache.ofbiz.entity.util.EntityQuery;
import org.apache.ofbiz.widget.WidgetWorker;
import org.apache.ofbiz.widget.model.CommonWidgetModels.Parameter;
import org.apache.ofbiz.widget.renderer.ScreenRenderException;
import org.apache.ofbiz.widget.renderer.ScreenStringRenderer;
import org.apache.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 += "&amp;";
}
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 &lt;node&gt; 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 &lt;image&gt; 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 &lt;label&gt; 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 &lt;link&gt; 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 &lt;sub-node&gt; 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);
}
}
}
}