2222 |
09 May 06 |
nicklas |
1 |
/* |
2222 |
09 May 06 |
nicklas |
$Id$ |
2222 |
09 May 06 |
nicklas |
3 |
|
4889 |
06 Apr 09 |
nicklas |
Copyright (C) 2006 Jari Häkkinen, Nicklas Nordborg |
2222 |
09 May 06 |
nicklas |
5 |
|
2304 |
22 May 06 |
jari |
This file is part of BASE - BioArray Software Environment. |
2304 |
22 May 06 |
jari |
Available at http://base.thep.lu.se/ |
2222 |
09 May 06 |
nicklas |
8 |
|
2222 |
09 May 06 |
nicklas |
BASE is free software; you can redistribute it and/or |
2222 |
09 May 06 |
nicklas |
modify it under the terms of the GNU General Public License |
4479 |
05 Sep 08 |
jari |
as published by the Free Software Foundation; either version 3 |
2222 |
09 May 06 |
nicklas |
of the License, or (at your option) any later version. |
2222 |
09 May 06 |
nicklas |
13 |
|
2222 |
09 May 06 |
nicklas |
BASE is distributed in the hope that it will be useful, |
2222 |
09 May 06 |
nicklas |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
2222 |
09 May 06 |
nicklas |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2222 |
09 May 06 |
nicklas |
GNU General Public License for more details. |
2222 |
09 May 06 |
nicklas |
18 |
|
2222 |
09 May 06 |
nicklas |
You should have received a copy of the GNU General Public License |
4515 |
11 Sep 08 |
jari |
along with BASE. If not, see <http://www.gnu.org/licenses/>. |
2222 |
09 May 06 |
nicklas |
21 |
*/ |
2222 |
09 May 06 |
nicklas |
22 |
package net.sf.basedb.util.jep; |
2222 |
09 May 06 |
nicklas |
23 |
|
2222 |
09 May 06 |
nicklas |
24 |
import net.sf.basedb.core.BaseException; |
5319 |
20 Apr 10 |
nicklas |
25 |
import net.sf.basedb.core.DynamicQuery; |
2222 |
09 May 06 |
nicklas |
26 |
import net.sf.basedb.core.RawDataType; |
2222 |
09 May 06 |
nicklas |
27 |
import net.sf.basedb.core.DbControl; |
2222 |
09 May 06 |
nicklas |
28 |
import net.sf.basedb.core.Metadata; |
2222 |
09 May 06 |
nicklas |
29 |
import net.sf.basedb.core.data.ReporterData; |
2222 |
09 May 06 |
nicklas |
30 |
import net.sf.basedb.core.query.Dynamic; |
2222 |
09 May 06 |
nicklas |
31 |
import net.sf.basedb.core.query.Expression; |
2981 |
30 Nov 06 |
nicklas |
32 |
import net.sf.basedb.util.BioAssaySetUtil; |
2222 |
09 May 06 |
nicklas |
33 |
|
2222 |
09 May 06 |
nicklas |
34 |
import java.util.Stack; |
2222 |
09 May 06 |
nicklas |
35 |
|
2222 |
09 May 06 |
nicklas |
36 |
import org.nfunk.jep.Node; |
2222 |
09 May 06 |
nicklas |
37 |
import org.nfunk.jep.ParseException; |
2222 |
09 May 06 |
nicklas |
38 |
|
2222 |
09 May 06 |
nicklas |
39 |
|
2222 |
09 May 06 |
nicklas |
40 |
/** |
5897 |
02 Dec 11 |
nicklas |
A JEP function class that adds a <code>rep(string)</code> or <code>mrep(string)</code> |
5897 |
02 Dec 11 |
nicklas |
function to a JEP expression parser. The function will look up the value of the reporter |
2222 |
09 May 06 |
nicklas |
property with the given name. For example: |
2222 |
09 May 06 |
nicklas |
<code>rep('sequence')</code> |
2222 |
09 May 06 |
nicklas |
<p> |
5897 |
02 Dec 11 |
nicklas |
If the <code>mrep</code> variant is used, the master reporter table is used, |
5897 |
02 Dec 11 |
nicklas |
otherwise the actual query can decide if it should use cloned reporter information |
5897 |
02 Dec 11 |
nicklas |
or not. |
5897 |
02 Dec 11 |
nicklas |
<p> |
2222 |
09 May 06 |
nicklas |
To be able to use this function it must be registered with the JEP |
2222 |
09 May 06 |
nicklas |
parser and, before the expression is evaluated, a reporter object must be set. |
2222 |
09 May 06 |
nicklas |
For example we can evaluate an expression for every reporter object: |
2222 |
09 May 06 |
nicklas |
53 |
|
2222 |
09 May 06 |
nicklas |
<pre class="code"> |
2222 |
09 May 06 |
nicklas |
DbControl dc = ... |
2222 |
09 May 06 |
nicklas |
RawBioAssay assay = ... |
2222 |
09 May 06 |
nicklas |
String expression = "rep('sequence')"; |
2222 |
09 May 06 |
nicklas |
ReporterFunction rep = new RepFunction(); |
2222 |
09 May 06 |
nicklas |
JEP jep = JepUtil.newJep(expression, rep); |
2222 |
09 May 06 |
nicklas |
DataResultIterator<RawData> result = |
2222 |
09 May 06 |
nicklas |
assay.getRawData().iterate(dc); |
2222 |
09 May 06 |
nicklas |
while (result.hasNext()) |
2222 |
09 May 06 |
nicklas |
63 |
{ |
2222 |
09 May 06 |
nicklas |
rep.setReporter(result.next().getReporter()); |
2222 |
09 May 06 |
nicklas |
String value = jep.getValue(); |
2222 |
09 May 06 |
nicklas |
// Do something with the value |
2222 |
09 May 06 |
nicklas |
67 |
} |
2222 |
09 May 06 |
nicklas |
result.close(); |
2222 |
09 May 06 |
nicklas |
</pre> |
2222 |
09 May 06 |
nicklas |
70 |
|
2222 |
09 May 06 |
nicklas |
@author Nicklas |
2222 |
09 May 06 |
nicklas |
@version 2.0 |
2222 |
09 May 06 |
nicklas |
@base.modified $Date$ |
2222 |
09 May 06 |
nicklas |
@see Jep |
5319 |
20 Apr 10 |
nicklas |
@see BioAssaySetUtil#createJepExpression(DbControl, String, DynamicQuery) |
2222 |
09 May 06 |
nicklas |
76 |
*/ |
2222 |
09 May 06 |
nicklas |
77 |
public class ReporterFunction |
2222 |
09 May 06 |
nicklas |
78 |
implements JepExpressionFunction |
2222 |
09 May 06 |
nicklas |
79 |
{ |
2222 |
09 May 06 |
nicklas |
80 |
|
2222 |
09 May 06 |
nicklas |
81 |
private final Metadata<ReporterData> metaData; |
2222 |
09 May 06 |
nicklas |
82 |
private final DbControl dc; |
5897 |
02 Dec 11 |
nicklas |
83 |
private final boolean master; |
2222 |
09 May 06 |
nicklas |
84 |
private int numParameters; |
2222 |
09 May 06 |
nicklas |
85 |
private ReporterData reporter; |
2222 |
09 May 06 |
nicklas |
86 |
|
2222 |
09 May 06 |
nicklas |
87 |
/** |
2222 |
09 May 06 |
nicklas |
Create a new instance of this function. The new instance cannot be used |
2222 |
09 May 06 |
nicklas |
to dynamically evaluate expressions. It should only be used for converting |
2222 |
09 May 06 |
nicklas |
JEP formulas to {@link Expression}:s. |
2222 |
09 May 06 |
nicklas |
@see Jep#formulaToExpression(String, JepFunction[]) |
2222 |
09 May 06 |
nicklas |
92 |
*/ |
2222 |
09 May 06 |
nicklas |
93 |
public ReporterFunction() |
2222 |
09 May 06 |
nicklas |
94 |
{ |
5897 |
02 Dec 11 |
nicklas |
95 |
this(false); |
5897 |
02 Dec 11 |
nicklas |
96 |
} |
5897 |
02 Dec 11 |
nicklas |
97 |
|
5897 |
02 Dec 11 |
nicklas |
98 |
/** |
5897 |
02 Dec 11 |
nicklas |
Create a new instance of this function. The new instance cannot be used |
5897 |
02 Dec 11 |
nicklas |
to dynamically evaluate expressions. It should only be used for converting |
5897 |
02 Dec 11 |
nicklas |
JEP formulas to {@link Expression}:s. If |
5897 |
02 Dec 11 |
nicklas |
102 |
|
5897 |
02 Dec 11 |
nicklas |
@since 3.1 |
5897 |
02 Dec 11 |
nicklas |
@param master TRUE to force using the master reporter table, FALSE to let |
5897 |
02 Dec 11 |
nicklas |
the query decide |
5897 |
02 Dec 11 |
nicklas |
106 |
*/ |
5897 |
02 Dec 11 |
nicklas |
107 |
public ReporterFunction(boolean master) |
5897 |
02 Dec 11 |
nicklas |
108 |
{ |
2222 |
09 May 06 |
nicklas |
109 |
this.dc = null; |
2222 |
09 May 06 |
nicklas |
110 |
this.metaData = null; |
5897 |
02 Dec 11 |
nicklas |
111 |
this.master = master; |
2222 |
09 May 06 |
nicklas |
112 |
} |
2222 |
09 May 06 |
nicklas |
113 |
|
2222 |
09 May 06 |
nicklas |
114 |
/** |
2222 |
09 May 06 |
nicklas |
Create a new instance of this function working with reporters. |
2222 |
09 May 06 |
nicklas |
116 |
*/ |
2222 |
09 May 06 |
nicklas |
117 |
public ReporterFunction(DbControl dc, RawDataType rawDataType) |
2222 |
09 May 06 |
nicklas |
118 |
{ |
2222 |
09 May 06 |
nicklas |
119 |
this.dc = dc; |
2222 |
09 May 06 |
nicklas |
120 |
this.metaData = Metadata.getInstance(ReporterData.class); |
5897 |
02 Dec 11 |
nicklas |
121 |
this.master = false; |
2222 |
09 May 06 |
nicklas |
122 |
} |
2222 |
09 May 06 |
nicklas |
123 |
|
2222 |
09 May 06 |
nicklas |
124 |
/* |
2222 |
09 May 06 |
nicklas |
From the JepFunction interface |
2222 |
09 May 06 |
nicklas |
126 |
------------------------------------------- |
2222 |
09 May 06 |
nicklas |
127 |
*/ |
2222 |
09 May 06 |
nicklas |
128 |
/** |
5897 |
02 Dec 11 |
nicklas |
@return The string "rep" or "mrep" |
2222 |
09 May 06 |
nicklas |
130 |
*/ |
6127 |
14 Sep 12 |
nicklas |
131 |
@Override |
2222 |
09 May 06 |
nicklas |
132 |
public String getFunctionName() |
2222 |
09 May 06 |
nicklas |
133 |
{ |
5897 |
02 Dec 11 |
nicklas |
134 |
return master ? "mrep" : "rep"; |
2222 |
09 May 06 |
nicklas |
135 |
} |
2222 |
09 May 06 |
nicklas |
136 |
// ------------------------------------------- |
2222 |
09 May 06 |
nicklas |
137 |
/* |
2222 |
09 May 06 |
nicklas |
From the JepExpressionFunction interface |
2222 |
09 May 06 |
nicklas |
139 |
------------------------------------------- |
2222 |
09 May 06 |
nicklas |
140 |
*/ |
2222 |
09 May 06 |
nicklas |
141 |
/** |
2222 |
09 May 06 |
nicklas |
Use the {@link Dynamic#reporter(String)} method to create an |
2222 |
09 May 06 |
nicklas |
expression referencing a reporter property. |
2222 |
09 May 06 |
nicklas |
144 |
*/ |
6127 |
14 Sep 12 |
nicklas |
145 |
@Override |
2222 |
09 May 06 |
nicklas |
146 |
public Expression toExpression(Node node) |
2222 |
09 May 06 |
nicklas |
147 |
{ |
2222 |
09 May 06 |
nicklas |
148 |
int numChildren = node.jjtGetNumChildren(); |
2222 |
09 May 06 |
nicklas |
149 |
if (numChildren != 1) |
2222 |
09 May 06 |
nicklas |
150 |
{ |
2222 |
09 May 06 |
nicklas |
151 |
throw new BaseException("Invalid number of expressions for 'rep' function: " + numChildren); |
2222 |
09 May 06 |
nicklas |
152 |
} |
5897 |
02 Dec 11 |
nicklas |
153 |
return Dynamic.reporter(Jep.nodeToString(node.jjtGetChild(0)), master ? false : null); |
2222 |
09 May 06 |
nicklas |
154 |
} |
2222 |
09 May 06 |
nicklas |
155 |
// ------------------------------------------- |
2222 |
09 May 06 |
nicklas |
156 |
/* |
2222 |
09 May 06 |
nicklas |
From the PostfixMathCommandI interface |
2222 |
09 May 06 |
nicklas |
158 |
------------------------------------------- |
2222 |
09 May 06 |
nicklas |
159 |
*/ |
2222 |
09 May 06 |
nicklas |
160 |
/** |
2222 |
09 May 06 |
nicklas |
@return Always 1 |
2222 |
09 May 06 |
nicklas |
162 |
*/ |
6127 |
14 Sep 12 |
nicklas |
163 |
@Override |
2222 |
09 May 06 |
nicklas |
164 |
public int getNumberOfParameters() |
2222 |
09 May 06 |
nicklas |
165 |
{ |
2222 |
09 May 06 |
nicklas |
166 |
return 1; |
2222 |
09 May 06 |
nicklas |
167 |
} |
6127 |
14 Sep 12 |
nicklas |
168 |
@Override |
2222 |
09 May 06 |
nicklas |
169 |
public void setCurNumberOfParameters(int n) |
2222 |
09 May 06 |
nicklas |
170 |
{ |
2222 |
09 May 06 |
nicklas |
171 |
this.numParameters = n; |
2222 |
09 May 06 |
nicklas |
172 |
} |
6127 |
14 Sep 12 |
nicklas |
173 |
@Override |
2474 |
31 Jul 06 |
nicklas |
174 |
public boolean checkNumberOfParameters(int n) |
2474 |
31 Jul 06 |
nicklas |
175 |
{ |
2474 |
31 Jul 06 |
nicklas |
176 |
return n == 1; |
2474 |
31 Jul 06 |
nicklas |
177 |
} |
6127 |
14 Sep 12 |
nicklas |
178 |
@Override |
6875 |
20 Apr 15 |
nicklas |
179 |
@SuppressWarnings({"unchecked", "rawtypes"}) |
2222 |
09 May 06 |
nicklas |
180 |
public void run(Stack stack) |
2222 |
09 May 06 |
nicklas |
181 |
throws ParseException |
2222 |
09 May 06 |
nicklas |
182 |
{ |
2222 |
09 May 06 |
nicklas |
183 |
if (stack == null || stack.empty()) |
2222 |
09 May 06 |
nicklas |
184 |
{ |
2222 |
09 May 06 |
nicklas |
185 |
throw new ParseException("Stack is empty"); |
2222 |
09 May 06 |
nicklas |
186 |
} |
2222 |
09 May 06 |
nicklas |
187 |
Object propertyName = stack.pop(); |
2222 |
09 May 06 |
nicklas |
188 |
if (propertyName instanceof String) |
2222 |
09 May 06 |
nicklas |
189 |
{ |
2222 |
09 May 06 |
nicklas |
190 |
stack.push(raw((String)propertyName)); |
2222 |
09 May 06 |
nicklas |
191 |
} |
2222 |
09 May 06 |
nicklas |
192 |
else |
2222 |
09 May 06 |
nicklas |
193 |
{ |
2222 |
09 May 06 |
nicklas |
194 |
throw new ParseException("Invalid parameter type: " + propertyName + "; expected string"); |
2222 |
09 May 06 |
nicklas |
195 |
} |
2222 |
09 May 06 |
nicklas |
196 |
} |
2222 |
09 May 06 |
nicklas |
197 |
// ------------------------------------------- |
2222 |
09 May 06 |
nicklas |
198 |
|
2222 |
09 May 06 |
nicklas |
199 |
/** |
2222 |
09 May 06 |
nicklas |
Set a new reporter object that will be used the next time the |
2222 |
09 May 06 |
nicklas |
JEP expression is evaluated. |
2222 |
09 May 06 |
nicklas |
@param reporter The reporter object to use |
2222 |
09 May 06 |
nicklas |
203 |
*/ |
2222 |
09 May 06 |
nicklas |
204 |
public void setReporter(ReporterData reporter) |
2222 |
09 May 06 |
nicklas |
205 |
{ |
2222 |
09 May 06 |
nicklas |
206 |
this.reporter = reporter; |
2222 |
09 May 06 |
nicklas |
207 |
} |
2222 |
09 May 06 |
nicklas |
208 |
/** |
2222 |
09 May 06 |
nicklas |
Get the current reporter object used when evaluating the JEP expression. |
2222 |
09 May 06 |
nicklas |
210 |
*/ |
2222 |
09 May 06 |
nicklas |
211 |
public ReporterData getReporter() |
2222 |
09 May 06 |
nicklas |
212 |
{ |
2222 |
09 May 06 |
nicklas |
213 |
return reporter; |
2222 |
09 May 06 |
nicklas |
214 |
} |
2222 |
09 May 06 |
nicklas |
215 |
|
2222 |
09 May 06 |
nicklas |
216 |
/** |
2222 |
09 May 06 |
nicklas |
Get the value of the specified property of the current raw data object. |
2222 |
09 May 06 |
nicklas |
This method uses Hibernate metadata to find the value. |
2222 |
09 May 06 |
nicklas |
@param propertyName The name of the raw data property |
4020 |
29 Nov 07 |
martin |
@return an java.lang.Object |
4020 |
29 Nov 07 |
martin |
@throws ParseException If the argument is null or 'reporter' not specified. |
2222 |
09 May 06 |
nicklas |
222 |
*/ |
2222 |
09 May 06 |
nicklas |
223 |
public Object raw(String propertyName) |
2222 |
09 May 06 |
nicklas |
224 |
throws ParseException |
2222 |
09 May 06 |
nicklas |
225 |
{ |
2222 |
09 May 06 |
nicklas |
226 |
if (reporter == null || propertyName == null) |
2222 |
09 May 06 |
nicklas |
227 |
{ |
2222 |
09 May 06 |
nicklas |
228 |
throw new ParseException("No reporter object has been specified for function rep('"+propertyName+"')"); |
2222 |
09 May 06 |
nicklas |
229 |
} |
5319 |
20 Apr 10 |
nicklas |
230 |
return metaData.getPropertyPath(propertyName, false).getValue(dc, reporter); |
2222 |
09 May 06 |
nicklas |
231 |
} |
2222 |
09 May 06 |
nicklas |
232 |
} |