001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010:
011: package org.mmbase.bridge.util.xml;
012:
013: import java.util.ArrayList;
014: import java.util.List;
015:
016: import org.mmbase.bridge.*;
017: import org.mmbase.util.logging.*;
018: import org.mmbase.util.functions.*;
019: import javax.servlet.http.HttpServletRequest;
020:
021: import javax.xml.xpath.*;
022:
023: /**
024: * Nodes of the bridge can have `virtual fields', which are in fact
025: * functions on the node. An example of such a function is "gui()". If
026: * you want to use these functions in an XSL transformation it is
027: * necessary to use this Xalan extension. The XSLT looks like this then:
028: *
029: <pre>
030: <xsl:stylesheet version = "1.0"
031: xmlns:xsl ="http://www.w3.org/1999/XSL/Transform"
032: xmlns:node ="org.mmbase.bridge.util.xml.NodeFunction"
033: >
034: ..
035: </pre>
036: You can then use a function like this if in the current template is a DOM Node with a 'field' subnode.
037: <pre>
038: ..
039: <img src="{$formatter_imgdb}{node:function(., 'cache(s(180x180))')}" />
040: </pre>
041: And otherwise you can also feed it a number:
042: <pre>
043: ..
044: <img src="{$formatter_imgdb}{node:function(string(@number), 'cache(s(180x180))')}" />
045: </pre>
046: Possibly even with the name of MMBase:
047: <pre>
048: ..
049: <img src="{$formatter_imgdb}{node:function('mmbase', string(@number), 'cache(s(180x180))')}" />
050: </pre>
051: *
052: *
053: * @author Michiel Meeuwissen
054: * @version $Id: NodeFunction.java,v 1.21 2007/04/09 19:10:27 michiel Exp $
055: * @since MMBase-1.6
056: */
057:
058: public class NodeFunction {
059: private static final Logger log = Logging
060: .getLoggerInstance(NodeFunction.class);
061:
062: /**
063: * Supposes the default cloud 'mmbase'.
064: * @param node The number (or alias) of the Node
065: * @param function The function (with arguments).
066: * @return The result of the function (as a String)
067: * @see #function(String, String, String)
068: */
069: public static String function(String node, String function) {
070: if (log.isDebugEnabled()) {
071: log.debug("calling with string '" + node + "' function: "
072: + function);
073: }
074: return function("mmbase", node, function);
075: }
076:
077: /**
078: * Note: Saxon cannnot distinguish this function from {@link #function(Cloud, String, String)},
079: * consider using {@link #saxonFunction(Object, String, String)} in stead.
080: * @param cloudName The name of the Cloud.
081: * @param number The number (or alias) of the Node
082: * @param function The function (with arguments).
083: * @return The result of the function (as a String)
084: */
085: public static String function(String cloudName, String number,
086: String function) {
087: log.debug("calling base for cloud " + cloudName);
088: try {
089: Cloud cloud = ContextProvider.getDefaultCloudContext()
090: .getCloud(cloudName);
091: return function(cloud, number, function);
092: } catch (Exception e) {
093: return "could not execute '" + function + "' on node '"
094: + number + "' (" + e.toString() + ")";
095: }
096: }
097:
098: /**
099: * Note: Saxon cannnot distinguish this function from {@link #function(String, String, String)},
100: * consider using {@link #saxonFunction(Object, String, String)} in stead.
101: */
102: public static String function(Cloud cloud, String number,
103: String function) {
104: return function(cloud, number, function, "");
105: }
106:
107: /**
108: * Saxon cannot distinguish the above two functions ({@link #function(String, String, String)},
109: * {@link #function(Cloud, String, String)}). So, you can help it and use this one in stead.
110: * @since MMBase-1.8.4
111: */
112: public static String saxonFunction(Object cloud, String number,
113: String function) {
114: if (cloud instanceof Cloud) {
115: return function((Cloud) cloud, number, function);
116: } else {
117: return function((String) cloud, number, function);
118: }
119: }
120:
121: /**
122: * @since MMBase-1.8
123: */
124: public static org.w3c.dom.Element nodeFunction(
125: org.w3c.dom.NodeList destination, Cloud cloud,
126: String number, String function, String arguments) {
127: // it only want to work withh a NodeList. I think my book sais that it should also work with
128: // Element, but no..
129:
130: try {
131: Node node = cloud.getNode(number);
132: Generator gen = new Generator(destination.item(0)
133: .getOwnerDocument());
134: java.util.List args = org.mmbase.util.StringSplitter
135: .splitFunctions(arguments);
136: if (log.isDebugEnabled()) {
137: log.debug("Executing " + function + " " + args + " on "
138: + node.getNumber());
139: }
140: Node resultNode = node.getFunctionValue(function, args)
141: .toNode();
142: org.w3c.dom.Element element = gen.add(resultNode);
143: if (log.isDebugEnabled()) {
144: log.debug("Returning "
145: + org.mmbase.util.xml.XMLWriter.write(element,
146: false));
147: }
148: return element;
149: } catch (Exception e) {
150: log.error("" + e + " " + Logging.stackTrace(e));
151: return null;
152: }
153: }
154:
155: /**
156: * It can be handy to supply a whole node, it will search for the field 'number' itself.
157: * @param node The number (or alias) of the Node
158: * @param function The function (with arguments).
159: * @return The result of the function (as a String)
160: * @throws XPathExpressionException if xpath fails
161: */
162: public static String function(org.w3c.dom.Node node, String function)
163: throws XPathExpressionException {
164: log.debug("calling with dom node");
165: XPath xpath = XPathFactory.newInstance().newXPath();
166: String number = xpath.evaluate("./field[@name='number']", node);
167: return function(number, function);
168: }
169:
170: /**
171: * @param request Meant to be an HttpServletRequest. If not, will be ignored (empty string e.g.).
172: * @since MMBase-1.8
173: */
174: public static String function(Cloud cloud, String number,
175: String function, Object request) {
176: log.debug("calling base on " + number + " for " + function);
177: Node node;
178: try {
179: node = cloud.getNode(number);
180:
181: Function func = null;
182: Parameters params = null;
183: if (function.indexOf("(") > -1) {
184: List args = new ArrayList();
185: String functionName = org.mmbase.util.functions.NodeFunction
186: .getFunctionNameAndFillArgs(function, args);
187: func = node.getFunction(functionName);
188: params = func.createParameters();
189: params.setAll(args);
190: } else {
191: func = node.getFunction(function);
192: params = func.createParameters();
193: }
194:
195: params.setIfDefined(Parameter.CLOUD, cloud);
196: if (request instanceof HttpServletRequest) {
197: params.setIfDefined(Parameter.REQUEST,
198: (HttpServletRequest) request);
199: }
200: return func.getFunctionValue(params).toString();
201: } catch (Throwable e) {
202: log.info("could not execute '" + function + "' on node '"
203: + number + "'", e);
204: return "could not execute " + function + " on node "
205: + number + "(" + e.getClass() + " "
206: + e.getMessage() + ")";
207: }
208: }
209:
210: /**
211: * It can be handy to supply a whole node, it will search for the field 'number' itself.
212: * @param cloud cloud to execute in
213: * @param node The number (or alias) of the Node
214: * @param function The function (with arguments).
215: * @return The result of the function (as a String)
216: * @throws javax.xml.transform.TransformerException if xpath fails
217: */
218: public static String function(Cloud cloud, org.w3c.dom.Node node,
219: String function) throws XPathExpressionException {
220: log.debug("calling with dom node");
221: XPath xpath = XPathFactory.newInstance().newXPath();
222: String number = xpath.evaluate("./field[@name='number']", node);
223: return function(cloud, number, function);
224: }
225:
226: /**
227: * @since MMBase-1.8
228: */
229: public static String guiName(Cloud cloud, String node) {
230: return cloud.getNode(node).getNodeManager().getGUIName();
231: }
232:
233: }
|