root/helma/helma/trunk/src/helma/scripting/rhino/HopObjectCtor.java

Revision 9557, 8.0 kB (checked in by hannes, 1 year ago)

Add static getCollection() method on HopObject constructors to generate collections programmatically and on the fly. Implement limit and offset collection properties for databases that support it (Postgresql + Mysql)

  • Property svn:eol-style set to native
  • Property cvs2svn:cvs-rev set to 1.6
  • Property svn:keywords set to Date Revision Author HeadURL Id
Line 
1 /*
2  * Helma License Notice
3  *
4  * The contents of this file are subject to the Helma License
5  * Version 2.0 (the "License"). You may not use this file except in
6  * compliance with the License. A copy of the License is available at
7  * http://adele.helma.org/download/helma/license.txt
8  *
9  * Copyright 1998-2003 Helma Software. All Rights Reserved.
10  *
11  * $RCSfile$
12  * $Author$
13  * $Revision$
14  * $Date$
15  */
16 package helma.scripting.rhino;
17
18 import java.lang.reflect.Constructor;
19 import java.lang.reflect.Method;
20 import java.util.Properties;
21
22 import helma.objectmodel.INode;
23 import helma.objectmodel.db.DbMapping;
24 import helma.objectmodel.db.DbKey;
25 import helma.objectmodel.db.Node;
26
27 import org.mozilla.javascript.*;
28
29 public class HopObjectCtor extends FunctionObject {
30
31     // init flag to trigger prototype compilation on
32     // static constructor property access
33     boolean initialized;
34     RhinoCore core;
35     Scriptable protoProperty;
36
37     static Method hopObjCtor;
38
39     static {
40         try {
41             hopObjCtor = HopObjectCtor.class.getMethod("jsConstructor", new Class[] {
42                 Context.class, Object[].class, Function.class, Boolean.TYPE });
43         } catch (NoSuchMethodException e) {
44             throw new RuntimeException("Error getting HopObjectCtor.jsConstructor()");
45         }
46     }
47
48     static final int attr = DONTENUM | PERMANENT;
49    
50     /**
51      * Create and install a HopObject constructor.
52      * Part of this is copied from o.m.j.FunctionObject.addAsConstructor().
53      *
54      * @param prototype
55      */
56     public HopObjectCtor(String protoName, RhinoCore core, Scriptable prototype) {
57         super(protoName, hopObjCtor, core.global);
58         this.core = core;
59         this.protoProperty = prototype;
60         addAsConstructor(core.global, prototype);
61         defineProperty("getById", new GetById(core.global), attr);
62         defineProperty("getCollection", new HopCollection(core.global), attr);
63     }
64
65     /**
66      *  This method is used as HopObject constructor from JavaScript.
67      */
68     public static Object jsConstructor(Context cx, Object[] args,
69                                        Function ctorObj, boolean inNewExpr)
70                          throws JavaScriptException {
71         HopObjectCtor ctor = (HopObjectCtor) ctorObj;
72         RhinoCore core = ctor.core;
73         String protoname = ctor.getFunctionName();
74
75         // if this is a java object prototype, create a new java object
76         // of the given class instead of a HopObject.
77         if (core.app.isJavaPrototype(protoname)) {
78             String classname = core.app.getJavaClassForPrototype(protoname);
79             try {
80                 Class clazz = Class.forName(classname);
81                 // try to get the constructor matching our arguments
82                 Class[] argsTypes = new Class[args.length];
83                 for (int i=0; i<argsTypes.length; i++) {
84                     argsTypes[i] = args[i] == null ? null : args[i].getClass();
85                 }
86                 Constructor cnst = clazz.getConstructor(argsTypes);
87                 // crate a new instance using the constructor
88                 Object obj = cnst.newInstance(args);
89                 return Context.toObject(obj, core.global);
90             } catch (Exception x) {
91                 System.err.println("Error in Java constructor: "+x);
92                 throw new EvaluatorException(x.toString());
93             }
94         } else {
95             INode node = new Node(protoname, protoname,
96                     core.app.getWrappedNodeManager());
97             Scriptable proto = core.getPrototype(protoname);
98             HopObject hobj = new HopObject(protoname, core, node, proto);
99
100             if (proto != null) {
101                 Object f = ScriptableObject.getProperty(proto, protoname);
102                 if (!(f instanceof Function)) {
103                     // backup compatibility: look up function constructor
104                     f = ScriptableObject.getProperty(proto, "__constructor__");
105                 }
106                 if (f instanceof Function) {
107                     ((Function) f).call(cx, core.global, hobj, args);
108                 }
109             }
110
111             return hobj;
112         }
113     }
114
115     public Object get(String name, Scriptable start) {
116         if (!initialized && core.isInitialized()) {
117             // trigger prototype compilation on static
118             // constructor property access
119             initialized = true;
120             core.getPrototype(getFunctionName());
121         }
122         return super.get(name, start);
123     }
124
125     public void put(String name, Scriptable start, Object value) {
126         if (value instanceof Function) {
127             // reset static function's parent scope, needed because of the way we compile
128             // prototype code, using the prototype objects as scope
129             Scriptable scriptable = (Scriptable) value;
130             while (scriptable != null) {
131                 Scriptable scope = scriptable.getParentScope();
132                 if (scope == protoProperty) {
133                     scriptable.setParentScope(core.global);
134                     break;
135                 }
136                 scriptable = scope;
137             }
138         }
139         super.put(name, start, value);
140     }
141
142     class GetById extends BaseFunction {
143
144         public GetById(Scriptable scope) {
145             ScriptRuntime.setFunctionProtoAndParent(this, scope);
146         }
147
148         /**
149          * Retrieve any persistent HopObject by type name and id.
150          *
151          * @return the HopObject or null if it doesn't exist
152          */
153         public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
154             if (args.length < 1 || args.length > 2)
155                 throw new IllegalArgumentException("Wrong number of arguments in getById()");
156             // If second argument is provided, use it as type name.
157             // Otherwise, use our own type name.
158             String type = args.length == 1 ?
159                     HopObjectCtor.this.getFunctionName() :
160                     Context.toString(args[1]);
161
162             DbMapping dbmap = core.app.getDbMapping(type);
163             if (dbmap == null)
164                 return null;
165             Object node = null;
166             try {
167                 DbKey key = new DbKey(dbmap, Context.toString(args[0]));
168                 node = core.app.getNodeManager().getNode(key);
169             } catch (Exception x) {
170                 return null;
171             }
172             return node == null ? null : Context.toObject(node, this);
173         }
174
175         public int getArity() {
176             return 1;
177         }
178
179         public int getLength() {
180             return 1;
181         }
182
183     }
184
185     class HopCollection extends BaseFunction {
186
187         public HopCollection(Scriptable scope) {
188             ScriptRuntime.setFunctionProtoAndParent(this, scope);
189         }
190
191         public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
192             if (args.length != 1) {
193                 throw new IllegalArgumentException("Wrong number of arguments in definePrototype()");
194             }
195             if (!(args[0] instanceof Scriptable)) {
196                 throw new IllegalArgumentException("Second argument to HopObject.definePrototype() must be Object");
197             }
198
199             Scriptable desc = (Scriptable) args[0];
200             Properties childmapping = core.scriptableToProperties(desc);
201             if (!childmapping.containsKey("collection")) {
202                 // if contained type isn't defined explicitly limit collection to our own type
203                 childmapping.put("collection", HopObjectCtor.this.getFunctionName());
204             }
205
206             Node node = new Node("HopQuery", null, core.app.getWrappedNodeManager());
207             Properties props = new Properties();
208             props.put("_children", childmapping);
209             DbMapping dbmap = new DbMapping(core.app, null, props);
210             dbmap.update();
211             node.setDbMapping(dbmap);
212             node.setState(Node.VIRTUAL);
213             return new HopObject("HopQuery", core, node, core.hopObjectProto);
214         }
215
216         public int getArity() {
217             return 1;
218         }
219
220         public int getLength() {
221             return 1;
222         }
223     }
224
225 }
Note: See TracBrowser for help on using the browser.