0
|
1 /*
|
|
2 * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
|
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 *
|
|
5 * This code is free software; you can redistribute it and/or modify it
|
|
6 * under the terms of the GNU General Public License version 2 only, as
|
|
7 * published by the Free Software Foundation.
|
|
8 *
|
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT
|
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12 * version 2 for more details (a copy is included in the LICENSE file that
|
|
13 * accompanied this code).
|
|
14 *
|
|
15 * You should have received a copy of the GNU General Public License version
|
|
16 * 2 along with this work; if not, write to the Free Software Foundation,
|
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
18 *
|
|
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
20 * CA 95054 USA or visit www.sun.com if you need additional information or
|
|
21 * have any questions.
|
|
22 *
|
|
23 */
|
|
24
|
|
25 package sun.jvm.hotspot.utilities.soql;
|
|
26
|
|
27 import java.util.*;
|
|
28 import sun.jvm.hotspot.oops.*;
|
|
29 import sun.jvm.hotspot.memory.*;
|
|
30 import sun.jvm.hotspot.runtime.*;
|
|
31 import sun.jvm.hotspot.utilities.*;
|
|
32
|
|
33 /**
|
|
34 * This is SOQL (Simple Object Query Language) engine. This
|
|
35 * uses JavaScript engine for the "select" and "where" expression
|
|
36 * parts.
|
|
37 */
|
|
38 public class SOQLEngine extends JSJavaScriptEngine {
|
|
39 public static synchronized SOQLEngine getEngine() {
|
|
40 if (soleInstance == null) {
|
|
41 soleInstance = new SOQLEngine();
|
|
42 }
|
|
43 return soleInstance;
|
|
44 }
|
|
45
|
|
46 /**
|
|
47 Query is of the form
|
|
48
|
|
49 select <java script code to select>
|
|
50 [ from [instanceof] <class name> [<identifier>]
|
|
51 [ where <java script boolean expression> ]
|
|
52 ]
|
|
53 */
|
|
54 public synchronized void executeQuery(String query, ObjectVisitor visitor)
|
|
55 throws SOQLException {
|
|
56 debugPrint("query : " + query);
|
|
57 StringTokenizer st = new StringTokenizer(query);
|
|
58 if (st.hasMoreTokens()) {
|
|
59 String first = st.nextToken();
|
|
60 if (! first.equals("select") ) {
|
|
61 throw new SOQLException("query syntax error: no 'select' clause");
|
|
62 }
|
|
63 } else {
|
|
64 throw new SOQLException("query syntax error: no 'select' clause");
|
|
65 }
|
|
66
|
|
67 int selectStart = query.indexOf("select");
|
|
68 int fromStart = query.indexOf("from");
|
|
69
|
|
70 String selectExpr = null;
|
|
71 String className = null;
|
|
72 boolean isInstanceOf = false;
|
|
73 String whereExpr = null;
|
|
74 String identifier = null;
|
|
75
|
|
76 if (fromStart != -1) {
|
|
77 selectExpr = query.substring(selectStart + "select".length(), fromStart);
|
|
78 st = new StringTokenizer(query.substring(fromStart + "from".length()));
|
|
79
|
|
80 if (st.hasMoreTokens()) {
|
|
81 String tmp = st.nextToken();
|
|
82 if (tmp.equals("instanceof")) {
|
|
83 isInstanceOf = true;
|
|
84 if (! st.hasMoreTokens()) {
|
|
85 throw new SOQLException("no class name after 'instanceof'");
|
|
86 }
|
|
87 className = st.nextToken();
|
|
88 } else {
|
|
89 className = tmp;
|
|
90 }
|
|
91 } else {
|
|
92 throw new SOQLException("query syntax error: class name must follow 'from'");
|
|
93 }
|
|
94
|
|
95 if (st.hasMoreTokens()) {
|
|
96 identifier = st.nextToken();
|
|
97 if (identifier.equals("where")) {
|
|
98 throw new SOQLException("query syntax error: identifier should follow class name");
|
|
99 }
|
|
100 if (st.hasMoreTokens()) {
|
|
101 String tmp = st.nextToken();
|
|
102 if (! tmp.equals("where")) {
|
|
103 throw new SOQLException("query syntax error: 'where' clause expected after 'from' clause");
|
|
104 }
|
|
105 int whereEnd = query.lastIndexOf("where") + 5; // "where".length
|
|
106 whereExpr = query.substring(whereEnd);
|
|
107 }
|
|
108 } else {
|
|
109 throw new SOQLException("query syntax error: identifier should follow class name");
|
|
110 }
|
|
111 } else { // no from clause
|
|
112 selectExpr = query.substring(selectStart + "select".length(), query.length());
|
|
113 }
|
|
114
|
|
115 executeQuery(new SOQLQuery(selectExpr, isInstanceOf, className, identifier, whereExpr), visitor);
|
|
116 }
|
|
117
|
|
118 private void executeQuery(SOQLQuery q, ObjectVisitor visitor) throws SOQLException {
|
|
119 InstanceKlass kls = null;
|
|
120 if (q.className != null) {
|
|
121 kls = SystemDictionaryHelper.findInstanceKlass(q.className);
|
|
122 if (kls == null) {
|
|
123 throw new SOQLException(q.className + " is not found!");
|
|
124 }
|
|
125 }
|
|
126
|
|
127
|
|
128 StringBuffer buf = new StringBuffer();
|
|
129 buf.append("function result(");
|
|
130 if (q.identifier != null) {
|
|
131 buf.append(q.identifier);
|
|
132 }
|
|
133 buf.append(") { return ");
|
|
134 buf.append(q.selectExpr.replace('\n', ' '));
|
|
135 buf.append("; }");
|
|
136
|
|
137 String selectCode = buf.toString();
|
|
138 debugPrint(selectCode);
|
|
139 String whereCode = null;
|
|
140 if (q.whereExpr != null) {
|
|
141 buf = new StringBuffer();
|
|
142 buf.append("function filter(");
|
|
143 buf.append(q.identifier);
|
|
144 buf.append(") { return ");
|
|
145 buf.append(q.whereExpr.replace('\n', ' '));
|
|
146 buf.append("; }");
|
|
147 whereCode = buf.toString();
|
|
148 debugPrint(whereCode);
|
|
149 } else {
|
|
150 whereCode = "filter = null;";
|
|
151 }
|
|
152
|
|
153 beginQuery();
|
|
154 // compile select expression and where condition
|
|
155 evalString(selectCode, "", 1);
|
|
156 evalString(whereCode, "", 1);
|
|
157
|
|
158 // iterate thru heap, if needed
|
|
159 if (q.className != null) {
|
|
160 try {
|
|
161 iterateOops(kls, visitor, q.isInstanceOf);
|
|
162 } finally {
|
|
163 endQuery();
|
|
164 }
|
|
165 } else {
|
|
166 // simple "select <expr>" query
|
|
167 try {
|
|
168 Object select = call("result", new Object[] {});
|
|
169 visitor.visit(select);
|
|
170 } catch (Exception e) {
|
|
171 e.printStackTrace();
|
|
172 }
|
|
173 }
|
|
174 }
|
|
175
|
|
176 private void dispatchObject(Oop oop, ObjectVisitor visitor, boolean filterExists) {
|
|
177 JSJavaObject jsObj = factory.newJSJavaObject(oop);
|
|
178 Object[] args = new Object[] { jsObj };
|
|
179 boolean b = true;
|
|
180
|
|
181 try {
|
|
182 if (filterExists) {
|
|
183 Object res = call("filter", args);
|
|
184 if (res instanceof Boolean) {
|
|
185 b = ((Boolean)res).booleanValue();
|
|
186 } else if (res instanceof Number) {
|
|
187 b = ((Number)res).intValue() != 0;
|
|
188 } else {
|
|
189 b = (res != null);
|
|
190 }
|
|
191 }
|
|
192
|
|
193 if (b) {
|
|
194 Object select = call("result", args);
|
|
195 visitor.visit(select);
|
|
196 }
|
|
197 } catch (Exception e) {
|
|
198 throw new RuntimeException(e);
|
|
199 }
|
|
200 }
|
|
201
|
|
202 private void iterateOops(final InstanceKlass ik, final ObjectVisitor visitor,
|
|
203 boolean includeSubtypes) {
|
|
204 ObjectHeap oh = VM.getVM().getObjectHeap();
|
|
205 oh.iterateObjectsOfKlass(new HeapVisitor() {
|
|
206 boolean filterExists;
|
|
207 public void prologue(long usedSize) {
|
|
208 filterExists = getScriptEngine().get("filter") != null;
|
|
209 }
|
|
210 public boolean doObj(Oop obj) {
|
|
211 dispatchObject(obj, visitor, filterExists);
|
|
212 return false;
|
|
213 }
|
|
214 public void epilogue() {}
|
|
215 }, ik, includeSubtypes);
|
|
216 }
|
|
217
|
|
218 // we create fresh ObjectReader and factory to avoid
|
|
219 // excessive cache across queries.
|
|
220 private void beginQuery() {
|
|
221 objReader = new ObjectReader();
|
|
222 factory = new JSJavaFactoryImpl();
|
|
223 }
|
|
224
|
|
225 // at the end of query we clear object reader cache
|
|
226 // and factory cache
|
|
227 private void endQuery() {
|
|
228 objReader = null;
|
|
229 factory = null;
|
|
230 }
|
|
231
|
|
232 protected ObjectReader getObjectReader() {
|
|
233 return objReader;
|
|
234 }
|
|
235
|
|
236 protected JSJavaFactory getJSJavaFactory() {
|
|
237 return factory;
|
|
238 }
|
|
239
|
|
240 protected boolean isQuitting() {
|
|
241 return false;
|
|
242 }
|
|
243
|
|
244 protected void quit() {
|
|
245 // do nothing
|
|
246 }
|
|
247
|
|
248 private static void debugPrint(String msg) {
|
|
249 if (debug) System.out.println(msg);
|
|
250 }
|
|
251
|
|
252 private static final boolean debug;
|
|
253 static {
|
|
254 debug = System.getProperty("sun.jvm.hotspot.utilities.soql.SOQLEngine.debug") != null;
|
|
255 }
|
|
256
|
|
257 protected SOQLEngine() {
|
|
258 super(debug);
|
|
259 start();
|
|
260 }
|
|
261
|
|
262 private ObjectReader objReader;
|
|
263 private JSJavaFactory factory;
|
|
264 private static SOQLEngine soleInstance;
|
|
265 }
|