001: /**********************************************************************
002: Copyright (c) 2008 Andy Jefferson and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015: Contributors:
016: ...
017: **********************************************************************/package org.jpox.store.query;
018:
019: import java.util.ArrayList;
020: import java.util.HashMap;
021: import java.util.List;
022: import java.util.Map;
023: import java.util.StringTokenizer;
024:
025: import org.jpox.exceptions.JPOXException;
026: import org.jpox.exceptions.JPOXUserException;
027: import org.jpox.store.query.Parser;
028: import org.jpox.util.Imports;
029: import org.jpox.util.Localiser;
030: import org.jpox.util.StringUtils;
031:
032: /**
033: * Base definition of a query compiler for a query language.
034: * Should be extended to compile details of individual query languages.
035: *
036: * @version $Revision$
037: */
038: public class QueryCompiler {
039: public static final int COMPILE_EXPLICIT_PARAMETERS = 1;
040: public static final int COMPILE_EXPLICIT_VARIABLES = 2;
041: public static final int COMPILE_SYNTAX = 3;
042: public static final int COMPILE_EXECUTION = 4;
043:
044: /** Localiser for messages. */
045: protected static final Localiser LOCALISER = Localiser
046: .getInstance("org.jpox.store.Localisation");
047:
048: /** Language of this query (e.g JDOQL, JPQL). */
049: protected String language;
050:
051: /** The query being compiled. */
052: protected Query query;
053:
054: /** Imports to use for the resolution of classes. */
055: protected Imports imports;
056:
057: /** Map of parameter values, keyed by their name. */
058: protected Map parameters;
059:
060: /** Flag for whether the current compile is for execution (using param values). */
061: protected boolean executionCompile = true;
062:
063: /** Parser for the query. */
064: protected Parser p = null;
065:
066: /** Candidate class for the query. May be updated during the compilation. */
067: protected Class candidateClass = null;
068:
069: /** Alias for the candidate class. */
070: protected String candidateAlias = "this";
071:
072: /** The parameter names. */
073: protected List parameterNames = null;
074:
075: /** Look-up for the parameter types, keyed by the name. */
076: protected Map parameterTypesByName = null;
077:
078: /** List of variable names. */
079: protected List variableNames = null;
080:
081: /** Look-up for the variables types, keyed by the name. */
082: protected Map variableTypesByName = null;
083:
084: /**
085: * Constructor for a compiler of java queries.
086: * @param query The query to compile
087: * @param imports The imports to use
088: * @param parameters Any parameters
089: */
090: public QueryCompiler(Query query, Imports imports, Map parameters) {
091: this .query = query;
092: this .imports = imports;
093: this .parameters = parameters;
094: this .candidateClass = query.getCandidateClass();
095: }
096:
097: /**
098: * Method to close the Compiler.
099: */
100: public void close() {
101: this .query = null;
102: this .imports = null;
103: this .variableNames = null;
104: this .parameterNames = null;
105: this .variableTypesByName = null;
106: this .parameterTypesByName = null;
107: this .parameters = null;
108: }
109:
110: /**
111: * Method to compile the query.
112: * @param type Type of compilation. This compiler only supports explicit parameters, explicit variables
113: * @return the compilation artifact (if any)
114: */
115: public Object compile(int type) {
116: switch (type) {
117: case COMPILE_EXPLICIT_PARAMETERS:
118: compileExplicitParameters();
119: return null;
120:
121: case COMPILE_EXPLICIT_VARIABLES:
122: compileExplicitVariables();
123: return null;
124:
125: default:
126: throw new JPOXException(
127: "Query Compiler doesnt support compilation of type "
128: + type);
129: }
130: }
131:
132: /**
133: * Accessor for the candidate class. May have been updated during the compile process.
134: * @return Candidate class
135: */
136: public Class getCandidateClass() {
137: return candidateClass;
138: }
139:
140: /**
141: * Accessor for the candidate alias.
142: * @return Candidate alias
143: */
144: public String getCandidateAlias() {
145: return candidateAlias;
146: }
147:
148: /**
149: * Accessor for the (explicit) parameter names.
150: * @return Parameter names
151: */
152: public String[] getParameterNames() {
153: if (parameterNames == null) {
154: return null;
155: }
156: return (String[]) parameterNames
157: .toArray(new String[parameterNames.size()]);
158: }
159:
160: /**
161: * Accessor for the parameter types keyed by the parameter name.
162: * Generated during compile of explicit parameters.
163: * @return Map of parameter type keyed by name
164: */
165: public Map getParameterTypesByName() {
166: return parameterTypesByName;
167: }
168:
169: /**
170: * Method to compile all parameters declared for this query.
171: * Takes the input "parameters" and populates "parameterNames", "parameterTypesByName" for convenience.
172: */
173: protected void compileExplicitParameters() {
174: parameterNames = new ArrayList();
175: parameterTypesByName = new HashMap();
176: String explicitParameters = query.getExplicitParameters();
177: if (explicitParameters != null
178: && explicitParameters.length() > 0) {
179: // Explicit parameters defined, so validate them
180: StringTokenizer t1 = new StringTokenizer(
181: explicitParameters, ",");
182: while (t1.hasMoreTokens()) {
183: StringTokenizer t2 = new StringTokenizer(
184: t1.nextToken(), " ");
185: if (t2.countTokens() != 2) {
186: throw new JPOXUserException(LOCALISER.msg("021018",
187: explicitParameters));
188: }
189:
190: String classDecl = t2.nextToken();
191: String parameterName = t2.nextToken();
192: if (!StringUtils
193: .isValidJavaIdentifierForJDOQL(parameterName)) {
194: throw new JPOXUserException(LOCALISER.msg("021019",
195: parameterName));
196: }
197:
198: if (parameterNames.contains(parameterName)) {
199: throw new JPOXUserException(LOCALISER.msg("021020",
200: parameterName));
201: }
202:
203: parameterNames.add(parameterName);
204: parameterTypesByName.put(parameterName, query
205: .resolveClassDeclaration(classDecl));
206: }
207: }
208: }
209:
210: /**
211: * Method to compile all variables declared for this query.
212: * Takes the input "variables" and populates "variableNames", "variableTypesByName" for convenience.
213: */
214: protected void compileExplicitVariables() {
215: variableNames = new ArrayList();
216: variableTypesByName = new HashMap();
217:
218: String explicitVariables = query.getExplicitVariables();
219: if (explicitVariables != null && explicitVariables.length() > 0) {
220: // Explicit variables defined, so validate them
221: StringTokenizer t1 = new StringTokenizer(explicitVariables,
222: ";");
223: while (t1.hasMoreTokens()) {
224: StringTokenizer t2 = new StringTokenizer(
225: t1.nextToken(), " ");
226: if (t2.countTokens() != 2) {
227: throw new JPOXUserException(LOCALISER.msg("021021",
228: explicitVariables));
229: }
230:
231: String classDecl = t2.nextToken();
232: String variableName = t2.nextToken();
233: if (!StringUtils
234: .isValidJavaIdentifierForJDOQL(variableName)) {
235: throw new JPOXUserException(LOCALISER.msg("021022",
236: variableName));
237: }
238:
239: if (parameterNames.contains(variableName)) {
240: throw new JPOXUserException(LOCALISER.msg("021023",
241: variableName));
242: }
243:
244: if (variableNames.contains(variableName)) {
245: throw new JPOXUserException(LOCALISER.msg("021024",
246: variableName));
247: }
248:
249: variableNames.add(variableName);
250: variableTypesByName.put(variableName, query
251: .resolveClassDeclaration(classDecl));
252: }
253: }
254: }
255: }
|