001: /**
002: * Copyright (C) 2001-2005 France Telecom
003: * Contact: alexandre.lefebvre@rd.francetelecom.com
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: *
019: */package org.objectweb.speedo.query.lib;
020:
021: import java.util.ArrayList;
022: import java.util.HashMap;
023: import java.util.Map;
024: import java.util.StringTokenizer;
025:
026: import org.objectweb.jorm.metainfo.api.Class;
027: import org.objectweb.jorm.metainfo.api.Manager;
028: import org.objectweb.jorm.util.api.Loggable;
029: import org.objectweb.medor.api.Field;
030: import org.objectweb.medor.api.MedorException;
031: import org.objectweb.medor.query.api.QueryTree;
032: import org.objectweb.medor.query.api.QueryTreeField;
033: import org.objectweb.medor.query.jorm.lib.ClassExtent;
034: import org.objectweb.medor.query.jorm.lib.PNameField;
035: import org.objectweb.medor.query.jorm.lib.QueryBuilder;
036: import org.objectweb.speedo.api.SpeedoException;
037: import org.objectweb.speedo.query.jdo.parser.SpeedoQLAbstractVisitor;
038: import org.objectweb.util.monolog.api.Logger;
039: import org.objectweb.util.monolog.api.LoggerFactory;
040:
041: /**
042: *
043: *
044: * @author Alexandre Lefebvre
045: */
046: public class SpeedoQueryHelper implements Loggable {
047:
048: /** Logger for monolog.
049: */
050: public Logger logger = null;
051: public boolean debug = false;
052:
053: /**
054: * the name of the current class
055: */
056: protected String curClass = null;
057:
058: protected Manager jmiManager;
059:
060: protected boolean includeSubClasses;
061:
062: /**
063: * ids is a temporary structure to store variables, parameters, name
064: * definitions, and build corresponding QueryTree(s)
065: * key: the name to resolve
066: * value: an IdValue object which contains the name, the paths, and the
067: * corresponding QueryTree (see the definition of IdValue object in
068: * SpeedoQLAbstractVisitor object)
069: */
070: protected Map ids = new HashMap();
071:
072: /**
073: * Values associated with each declared identifiers
074: */
075: protected class IdValue {
076: // Paths used in the select and where clauses starting with the
077: // corresponding id
078: private ArrayList paths = null;
079:
080: // abstract schema name or collection values path
081: public String[] name = null;
082:
083: // The query tree which corresponds to the id and the paths
084: public QueryTree qt = null;
085:
086: // one of 4 possibilities
087: public int nameType = SpeedoQLAbstractVisitor.UNDEFINED;
088:
089: public String alias;
090:
091: public IdValue(String[] name, int nameType) {
092: this ();
093: this .name = name;
094: this .nameType = nameType;
095: }
096:
097: public IdValue(String pathName, int nameType) {
098: this (pathName);
099: this .nameType = nameType;
100: }
101:
102: public IdValue(String pathName) {
103: this ();
104: name = splitPath(pathName);
105: }
106:
107: public IdValue() {
108: paths = new ArrayList();
109: }
110:
111: public void addPath(String path) {
112: if (!paths.contains(path)) {
113: paths.add(path);
114: }
115: }
116:
117: public String[] getSplitedPath(int idx) {
118: return splitPath((String) paths.get(idx));
119: }
120:
121: public String getMergedPath(int idx) {
122: return (String) paths.get(idx);
123: }
124:
125: public int getDeclaredPathLength() {
126: return paths.size();
127: }
128:
129: /**
130: * this method returns the internal representation of an IdValue.
131: * this method is not optimized, because we don't need to call it
132: * a lot of times.
133: */
134: public String toString() {
135: String resName = new String();
136:
137: if (name != null) {
138: for (int i = 0; i < name.length; i++)
139: resName += name[i] + ".";
140:
141: resName = "[name="
142: + resName.substring(0, resName.length() - 1)
143: + "]";
144: } else
145: resName = "[name=null] ";
146:
147: String resPath = new String();
148: for (int i = 0; i < paths.size(); i++)
149: resPath += (String) paths.get(i) + " & ";
150:
151: return resName + " - [path=" + resPath + "] - [QT="
152: + ((qt == null) ? "null" : "something :-)") + "]";
153: }
154: }
155:
156: /**
157: * split a dot separated path into tokens
158: */
159: protected String[] splitPath(String path) {
160: StringTokenizer st = new StringTokenizer(path, ".");
161: String[] ret = new String[st.countTokens()];
162: for (int i = 0; i < ret.length; i++) {
163: ret[i] = st.nextToken();
164: }
165: return ret;
166: }
167:
168: protected QueryTreeField define(QueryBuilder theqb, String id,
169: String alias) throws MedorException, SpeedoException {
170: String[] path = splitPath(id);
171:
172: if (!theqb.contains(path[0])) {
173: IdValue idv = (IdValue) ids.get(path[0]);
174: String[] name = idv.name;
175:
176: PNameField pnf;
177: if (name.length == 1) {
178: pnf = extent(name[0], path[0]);
179: theqb.define(path[0], pnf);
180: } else {
181: pnf = (PNameField) define(theqb, mergePath(name), alias);
182: if (!path[0].equals(alias)) {
183: theqb.define(path[0], pnf);
184: }
185: }
186: }
187: return theqb.navigate(path, alias);
188: }
189:
190: protected PNameField extent(String classname, String alias)
191: throws SpeedoException, MedorException {
192: if (classname == null) {
193: throw new NullPointerException("class name not defined");
194: }
195: Class theClass = jmiManager.getClass(classname);
196: if (theClass == null) {
197: throw new SpeedoException(
198: "Class '"
199: + classname
200: + "' has not been declared in the jorm meta information");
201: }
202: ClassExtent ext = new ClassExtent(theClass, alias,
203: Field.PNAMENAME, false);
204: if (classname.equals(this .curClass)) {
205: ext.setWithSubClasses(includeSubClasses);
206: }
207: return (PNameField) ext.getField(ext.getPNameFieldName());
208: }
209:
210: protected String mergePath(String[] path, int begin, int length) {
211: if (length == 0)
212: return "";
213: StringBuffer ret = new StringBuffer();
214: for (int i = begin; i < (begin + length); i++) {
215: ret.append(path[i]);
216: ret.append('.');
217: }
218: ret.deleteCharAt(ret.length() - 1);
219: return ret.toString();
220: }
221:
222: /**
223: * @param path the input path
224: * @return the merge tokens into a dot separated path
225: */
226: protected String mergePath(String[] path) {
227: return (mergePath(path, 0, path.length));
228: }
229:
230: // IMPLEMENTATION OF THE Loggable INTERFACE //
231: //------------------------------------------//
232:
233: public void setLogger(Logger logger) {
234: this .logger = logger;
235: }
236:
237: public Logger getLogger() {
238: return logger;
239: }
240:
241: public void setLoggerFactory(LoggerFactory loggerFactory) {
242: }
243:
244: public LoggerFactory getLoggerFactory() {
245: return null;
246: }
247:
248: }
|