KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > functions > NodeFunction


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.util.functions;
11
12 import java.util.*;
13 import org.mmbase.module.core.MMObjectNode;
14 import org.mmbase.module.core.MMObjectBuilder;
15 import org.mmbase.bridge.*;
16
17 import org.mmbase.util.logging.Logger;
18 import org.mmbase.util.logging.Logging;
19
20 /**
21  * A NodeFunction represents a function on a node instances of this builder. This means
22  * that it always has one implicit node argument. This node-argument needs not be mentioned in
23  * the Parameter array of the constructor.
24  *
25  * @author Michiel Meeuwissen
26  * @version $Id: NodeFunction.java,v 1.21 2006/03/02 17:25:13 michiel Exp $
27  * @see org.mmbase.module.core.MMObjectBuilder#executeFunction
28  * @see org.mmbase.bridge.Node#getFunctionValue
29  * @see org.mmbase.util.functions.BeanFunction
30  * @since MMBase-1.8
31  */

32
33 public abstract class NodeFunction extends AbstractFunction {
34
35     private static final Logger log = Logging.getLoggerInstance(NodeFunction.class);
36
37     /**
38      * Utility function, for easy call of function on node by one string.
39      */

40     public static FieldValue getFunctionValue(Node node, String JavaDoc function) {
41         if(node == null) {
42             log.warn("Tried to execute node-function on null!");
43             return null;
44         }
45         List args = new ArrayList();
46         String JavaDoc functionName = getFunctionNameAndFillArgs(function, args);
47         if (log.isDebugEnabled()) {
48             log.debug("Executing " + functionName + " " + args + " on " + node.getNumber());
49         }
50
51         return node.getFunctionValue(functionName, args);
52     }
53
54     public static String JavaDoc getFunctionNameAndFillArgs(String JavaDoc function, java.util.List JavaDoc args) {
55         String JavaDoc functionName = function;
56         int pos1 = function.indexOf('(');
57         if (pos1 != -1) {
58             int pos2 = function.lastIndexOf(')');
59             if (pos2 != -1) {
60                 functionName = function.substring(0, pos1);
61                 java.util.List JavaDoc args2 = org.mmbase.util.StringSplitter.splitFunctions(function.subSequence(pos1 + 1, pos2));
62                 args.addAll(args2);
63             }
64         }
65         return functionName;
66     }
67
68     public NodeFunction(String JavaDoc name, Parameter[] def, ReturnType returnType) {
69         super(name, getNodeParameterDef(def), returnType);
70     }
71
72     protected static Parameter[] getNodeParameterDef(Parameter[] def) {
73         List defList = Arrays.asList(def);
74         if (defList.contains(Parameter.NODE) && defList.contains(Parameter.CLOUD)) {
75             return new Parameter[] { new Parameter.Wrapper(def), Parameter.CORENODE};
76         } else if (defList.contains(Parameter.NODE)) {
77             return new Parameter[] { new Parameter.Wrapper(def), Parameter.CLOUD, Parameter.CORENODE};
78         } else if (defList.contains(Parameter.CLOUD)) {
79             return new Parameter[] { new Parameter.Wrapper(def), Parameter.NODE, Parameter.CORENODE};
80         } else {
81             return new Parameter[] { new Parameter.Wrapper(def), Parameter.NODE, Parameter.CLOUD, Parameter.CORENODE};
82         }
83     }
84
85     /**
86      * Returns a new instance of NodeInstanceFunction, which represents an actual Function.
87      */

88     final public Function newInstance(MMObjectNode node) {
89         return new NodeInstanceFunction(node);
90     }
91
92     /**
93      * Implements the function on a certain node. Override this method <em>or</em> it's bridge
94      * counter-part {@link #getFunctionValue(org.mmbase.bridge.Node, Parameters)}. Overriding the
95      * bridge version has two advantages. It's easier, and mmbase security will be honoured. That
96      * last thing is of course not necesary if you are not going to use other nodes.
97      *
98      * XXX: made final because it does not work well if you don't implement a bridge version
99      */

100     protected final Object JavaDoc getFunctionValue(final MMObjectNode coreNode, final Parameters parameters) {
101         if (coreNode == null) throw new RuntimeException JavaDoc("No node argument given for " + this + "(" + parameters + ")!");
102         Node node = (Node) parameters.get(Parameter.NODE);
103         if (node == null) {
104             Cloud cloud = (Cloud) parameters.get(Parameter.CLOUD);
105             if (cloud == null) {
106                 // lets try this
107
try {
108                     cloud = org.mmbase.bridge.ContextProvider.getDefaultCloudContext().getCloud("mmbase", "class", null);
109                 } catch (org.mmbase.security.SecurityException se) {
110                     // perhaps class-security not implemented by security implementation.
111
log.warn("" + se.getMessage());
112                     cloud = org.mmbase.bridge.ContextProvider.getDefaultCloudContext().getCloud("mmbase");
113                 }
114                 if (cloud == null) {
115                     throw new RuntimeException JavaDoc("No cloud argument given" + this + "(" + parameters + ")!" + Logging.stackTrace());
116                 }
117             }
118             if (coreNode instanceof org.mmbase.module.core.VirtualNode) {
119                 node = new org.mmbase.bridge.implementation.VirtualNode((org.mmbase.module.core.VirtualNode) coreNode, cloud);
120             } else {
121                 int number = coreNode.getNumber();
122                 if (number == -1) {
123                     // must be in transaction or uncommited node
124
String JavaDoc tmpNumber = coreNode.getStringValue(MMObjectBuilder.TMP_FIELD_NUMBER);
125                     if (cloud.hasNode(tmpNumber)) {
126                         node = cloud.getNode(tmpNumber);
127                     } else {
128                         // last resort..., we're really desperate now.
129
// This happens when calling gui() in transaction.
130
// Perhaps we need something like a public new BasicNode(MMobjectNode, Cloud). Abusing VirtualNode for similar purpose now.
131
org.mmbase.module.core.VirtualNode virtual = new org.mmbase.module.core.VirtualNode(coreNode.getBuilder());
132                         Iterator i = coreNode.getValues().entrySet().iterator();
133                         while (i.hasNext()) {
134                             Map.Entry entry = (Map.Entry) i.next();
135                             virtual.storeValue((String JavaDoc) entry.getKey(), entry.getValue());
136                         }
137                         node = new org.mmbase.bridge.implementation.VirtualNode(virtual, cloud);
138                     }
139                 } else {
140                     if (cloud.mayRead(number)) {
141                         node = cloud.getNode(number);
142                     } else {
143                         log.warn("Could not produce Bridge Node for '" + number + "', cannot execute node function.");
144                         return null;
145                     }
146                 }
147             }
148             parameters.set(Parameter.NODE, node);
149         }
150         return getFunctionValue(node, parameters);
151
152     }
153
154     /**
155      * Utility method to convert a {@link org.mmbase.bridge.Node} to a a {@link org.mmbase.module.core.MMObjectNode}.
156      */

157     protected final MMObjectNode getCoreNode(final MMObjectBuilder builder, final Node node) {
158         if (node instanceof org.mmbase.bridge.implementation.VirtualNode) {
159             return ((org.mmbase.bridge.implementation.VirtualNode) node).getNodeRef();
160         } else {
161             return builder.getNode(node.getNumber());
162         }
163
164     }
165
166     /**
167      */

168     protected abstract Object JavaDoc getFunctionValue(Node node, Parameters parameters);
169
170     protected Node getNode(Parameters parameters) {
171         if (! parameters.containsParameter(Parameter.NODE)) {
172             throw new IllegalArgumentException JavaDoc("The function " + toString() + " requires a node argument");
173         }
174         Node node = (Node) parameters.get(Parameter.NODE);
175         if (node == null) {
176             throw new IllegalArgumentException JavaDoc("The '" + Parameter.NODE + "' argument of " + getClass() + " " + toString() + " must not be null ");
177         }
178         return node;
179     }
180
181     /**
182      * To implement a NodeFunction, you must override {@link #getFunctionValue(Node, Parameters)}.
183      * This one can be overriden if the same function must <em>also</em> be a builder function.
184      */

185     public Object JavaDoc getFunctionValue(Parameters parameters) {
186         return getFunctionValue(getNode(parameters), parameters);
187     }
188
189     /**
190      * This represents the function on one specific Node. This is instantiated when new Istance
191      * if called on a NodeFunction.
192      */

193     private class NodeInstanceFunction extends WrappedFunction {
194
195         protected MMObjectNode node;
196
197         public NodeInstanceFunction(MMObjectNode node) {
198             super(NodeFunction.this);
199             this.node = node;
200         }
201         //javadoc inherited
202
public final Object JavaDoc getFunctionValue(Parameters parameters) {
203             parameters.set(Parameter.CORENODE, node);
204             return NodeFunction.this.getFunctionValue(node, parameters);
205
206         }
207
208         public String JavaDoc toString() {
209             return NodeFunction.this.toString() + " for node " + node.getNumber();
210         }
211     }
212
213 }
214
215
216
Popular Tags