]> gerrit.simantics Code Review - simantics/r.git/blob - org.simantics.r.scl/src/org/rosuda/REngine/REngine.java
(refs #6833) Test RExp inheritance in SCL
[simantics/r.git] / org.simantics.r.scl / src / org / rosuda / REngine / REngine.java
1 package org.rosuda.REngine;
2
3 import java.lang.reflect.Method;
4
5 /** REngine is an abstract base class for all implementations of R engines. Subclasses can implement interfaces to R in many different ways.
6  Clients should always use methods this class instead of its direct subclasses in order to maintian compatibility with any R engine implementation.
7  The canonical way of obtaining a new engine is to call {@link #engineForClass}. All subclasses must implement <code>createEngine()</code> method. */
8 public abstract class REngine {
9     /** last created engine or <code>null</code> if there is none */
10     protected static REngine lastEngine = null;
11         
12     /** this is the designated constructor for REngine classes. It uses reflection to call createEngine method on the given REngine class.
13         @param klass fully qualified class-name of a REngine implementation
14         @return REngine implementation or <code>null</code> if <code>createEngine</code> invokation failed */
15     public static REngine engineForClass(String klass) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, java.lang.reflect.InvocationTargetException {
16                 Class cl=Class.forName(klass);
17                 if (cl==null) throw(new ClassNotFoundException("can't find engine class "+klass));
18                 Method m=cl.getMethod("createEngine",(Class[])null);
19                 Object o=m.invoke(null,(Object[])null);
20                 return lastEngine=(REngine)o;
21     }
22
23         /** This is the extended constructor for REngine classes. It uses reflection to call createEngine method on the given REngine class with some additional control over the engine. Note that not all engines may support the extended version.
24          @param klass fully qualified class-name of a REngine implementation
25          @param args arguments to pass to R for initialization
26          @param callbacks delegate for REngine callbacks or <code>null</code> if callbacks won't be serviced (engine may not support callbacks)
27          @param runREPL if <code>true</code> then REPL will be started (if supported by the engine)
28          @return REngine implementation or <code>null</code> if <code>createEngine</code> invokation failed */
29         public static REngine engineForClass(String klass, String[] args, REngineCallbacks callbacks, boolean runREPL) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, java.lang.reflect.InvocationTargetException {
30                 Class cl = Class.forName(klass);
31                 if (cl == null) throw new ClassNotFoundException("can't find engine class " + klass);
32                 Method m = cl.getMethod("createEngine", new Class[] { String[].class, REngineCallbacks.class, Boolean.TYPE });
33                 Object o = m.invoke(null, new Object[] { args, callbacks, new Boolean(runREPL) });
34                 return lastEngine = (REngine)o;
35         }
36         
37     /** retrieve the last created engine
38                 @return last created engine or <code>null</code> if no engine was created yet */
39     public static REngine getLastEngine() {
40                 return lastEngine;
41     }
42
43         /** parse a string into an expression vector
44                 @param text string to parse
45                 @param resolve resolve the resulting REXP (<code>true</code>) or just return a reference (<code>false</code>)
46             @return parsed expression */
47         public abstract REXP parse(String text, boolean resolve) throws REngineException;
48
49         /** evaluate an expression vector
50                 @param what an expression (or vector of such) to evaluate
51                 @param where environment to evaluate in (use <code>null</code> for the global environemnt and/or if environments are not supported by the engine)
52                 @param resolve resolve the resulting REXP or just return a reference
53                 @return the result of the evaluation of the last expression */
54     public abstract REXP eval(REXP what, REXP where, boolean resolve) throws REngineException, REXPMismatchException;
55
56         /** assign into an environment
57                 @param symbol symbol name
58                 @param value value to assign
59                 @param env environment to assign to (use <code>null</code> for the global environemnt and/or if environments are not supported by the engine) */
60     public abstract void assign(String symbol, REXP value, REXP env) throws REngineException, REXPMismatchException;
61
62         /** get a value from an environment
63                 @param symbol symbol name
64                 @param env environment (use <code>null</code> for the global environemnt and/or if environments are not supported by the engine)
65                 @param resolve resolve the resulting REXP or just return a reference            
66                 @return value */
67     public abstract REXP get(String symbol, REXP env, boolean resolve) throws REngineException, REXPMismatchException;
68
69         /** fetch the contents of the given reference. The resulting REXP may never be REXPReference. The engine should raise a {@link #REngineException} exception if {@link #supportsReferences()} returns <code>false</code>.
70                 @param ref reference to resolve
71                 @return resolved reference */
72         public abstract REXP resolveReference(REXP ref) throws REngineException, REXPMismatchException;
73
74         /** create a reference by pushing local data to R and returning a reference to the data. If ref is a reference it is returned as-is. The engine should raise a {@link #REngineException} exception if {@link #supportsReferences()} returns <code>false</code>.
75          @param value to create reference to
76          @return reference to the value */
77         public abstract REXP createReference(REXP value) throws REngineException, REXPMismatchException;
78
79         /** removes reference from the R side. This method is called automatically by the finalizer of <code>REXPReference</code> and should never be called directly.
80          @param ref reference to finalize */
81         public abstract void finalizeReference(REXP ref) throws REngineException, REXPMismatchException;
82         
83         /** get the parent environemnt of an environemnt
84          @param env environment to query
85          @param resolve whether to resolve the resulting environment reference
86          @return parent environemnt of env */
87         public abstract REXP getParentEnvironment(REXP env, boolean resolve) throws REngineException, REXPMismatchException;
88         
89         /** create a new environemnt
90          @param parent parent environment
91          @param resolve whether to resolve the reference to the environemnt (usually <code>false</code> since the returned environment will be empty)
92          @return resulting environment */
93         public abstract REXP newEnvironment(REXP parent, boolean resolve) throws REngineException, REXPMismatchException;
94         
95     /** convenince method equivalent to <code>eval(parse(text, false), where, resolve);</code>
96          @param text to parse (see {@link #parse})
97          @param where environment to evaluate in (see {@link #eval})
98          @param resolve whether to resolve the resulting reference or not (see {@link #eval})
99          @return result */
100         public REXP parseAndEval(String text, REXP where, boolean resolve) throws REngineException, REXPMismatchException {
101                 REXP p = parse(text, false);
102                 return eval(p, where, resolve);
103         }
104
105     /** convenince method equivalent to <code>eval(parse(cmd, false), null, true);</code>
106          @param cmd expression to parse (see {@link #parse})
107          @return result */
108     public REXP parseAndEval(String cmd) throws REngineException, REXPMismatchException { return parseAndEval(cmd, null, true); };
109         
110         /** performs a close operation on engines that support it. The engine may not be used after <code>close()</code> returned <code>true</code>. This operation is optional and will always return <code>false</code> if not implemented.
111          @return <code>true</code> if the close opetaion was successful, <code>false</code> otherwise. */
112         public boolean close() { return false; }
113         
114         //--- capabilities ---
115         /** check whether this engine supports references to R objects
116          @return <code>true</code> if this engine supports references, <code>false/code> otherwise */
117         public boolean supportsReferences() { return false; }
118         /** check whether this engine supports handing of environments (if not, {@link #eval} and {@link #assign} only support the global environment denoted by <code>null</code>).
119          @return <code>true</code> if this engine supports environments, <code>false/code> otherwise */
120         public boolean supportsEnvironments() { return false; }
121         /** check whether this engine supports REPL (Read-Evaluate-Print-Loop) and corresponding callbacks.
122          @return <code>true</code> if this engine supports REPL, <code>false/code> otherwise */
123         public boolean supportsREPL() { return false; }
124         /** check whether this engine supports locking ({@link #lock}, {@link #tryLock} and {@link #unlock}).
125          @return <code>true</code> if this engine supports REPL, <code>false/code> otherwise */
126         public boolean supportsLocking() { return false; }
127
128         //--- convenience methods --- (the REXPMismatchException catches should be no-ops since the value type is guaranteed in the call to assign)
129         /** convenience method equivalent to <code>assign(symbol, new REXPDouble(d), null)</code> (see {@link #assign(String, REXP, REXP)})
130          @param symbol symbol name to assign to
131          @param d values to assign */
132         public void assign(String symbol, double[] d) throws REngineException { try { assign(symbol, new REXPDouble(d), null); } catch (REXPMismatchException e) { throw(new REngineException(this, "REXPMismatchException in assign(,double[]): "+e)); } }
133         /** convenience method equivalent to <code>assign(symbol, new REXPInteger(d), null)</code> (see {@link #assign(String, REXP, REXP)})
134          @param symbol symbol name to assign to
135          @param d values to assign */
136         public void assign(String symbol, int[] d) throws REngineException { try { assign(symbol, new REXPInteger(d), null); } catch (REXPMismatchException e) { throw(new REngineException(this, "REXPMismatchException in assign(,int[]): "+e)); } }
137         /** convenience method equivalent to <code>assign(symbol, new REXPString(d), null)</code> (see {@link #assign(String, REXP, REXP)})
138          @param symbol symbol name to assign to
139          @param d values to assign */
140         public void assign(String symbol, String[] d) throws REngineException { try { assign(symbol, new REXPString(d), null); } catch (REXPMismatchException e) { throw(new REngineException(this, "REXPMismatchException in assign(,String[]): "+e)); } }
141         /** convenience method equivalent to <code>assign(symbol, new REXPRaw(d), null)</code> (see {@link #assign(String, REXP, REXP)})
142          @param symbol symbol name to assign to
143          @param d values to assign */
144         public void assign(String symbol, byte[] d) throws REngineException { try { assign(symbol, new REXPRaw(d), null); } catch (REXPMismatchException e) { throw(new REngineException(this, "REXPMismatchException in assign(,byte[]): "+e)); } }
145         /** convenience method equivalent to <code>assign(symbol, new REXPString(d), null)</code> (see {@link #assign(String, REXP, REXP)})
146          @param symbol symbol name to assign to
147          @param d value to assign */
148         public void assign(String symbol, String d) throws REngineException { try { assign(symbol, new REXPString(d), null); } catch (REXPMismatchException e) { throw(new REngineException(this, "REXPMismatchException in assign(,String[]): "+e)); } }
149         /** convenience method equivalent to <code>assign(symbol, value, null)</code> (see {@link #assign(String, REXP, REXP)})
150          @param symbol symbol name to assign to
151          @param value values to assign */
152         public void assign(String symbol, REXP value) throws REngineException, REXPMismatchException { assign(symbol, value, null); }
153         
154         //--- locking API ---
155         /** attempts to obtain a lock for this R engine synchronously (without waiting for it).
156             <br>Note: check for {@link #supportsLocking()} before relying on this capability. If not implemented, always returns 0.
157          @return 0 if the lock could not be obtained (R engine is busy) and some other value otherwise -- the returned value must be used in a matching call to {@link #unlock(int)}. */
158         public synchronized int tryLock() { return 0; }
159
160         /** obtains a lock for this R engine, waiting until it becomes available.
161          <br>Note: check for {@link #supportsLocking()} before relying on this capability. If not implemented, always returns 0.
162          @return value that must be passed to {@link #unlock} in order to release the lock */
163         public synchronized int lock() { return 0; }
164
165         /** releases a lock previously obtained by {@link #lock()} or {@link #tryLock()}.
166          <br>Note: check for {@link #supportsLocking()} before relying on this capability.  If not implemented, has no effect.
167          @param lockValue value returned by {@link #lock()} or {@link #tryLock()}. */    
168         public synchronized void unlock(int lockValue) {}
169
170         public String toString() {
171                 return super.toString()+((lastEngine==this)?"{last}":"");
172         }
173         
174         public REXP wrap(Object o){
175                 return REXPWrapper.wrap(o); 
176         }
177 }