001: /**
002: * Speedo: an implementation of JDO compliant personality on top of JORM generic
003: * I/O sub-system.
004: * Copyright (C) 2001-2006 France Telecom
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * Contact: speedo@objectweb.org
021: *
022: * Authors: S. Chassande-Barrioz
023: *
024: */package org.objectweb.speedo.query.lib;
025:
026: import org.objectweb.jorm.api.PClassMapping;
027: import org.objectweb.jorm.api.PException;
028: import org.objectweb.jorm.api.PMapper;
029: import org.objectweb.jorm.lib.JormPathHelper;
030: import org.objectweb.jorm.type.api.PType;
031: import org.objectweb.jorm.type.api.PTypeSpace;
032: import org.objectweb.medor.eval.prefetch.api.PrefetchBufferFactory;
033: import org.objectweb.medor.expression.api.Expression;
034: import org.objectweb.medor.expression.api.Operand;
035: import org.objectweb.medor.expression.api.Operator;
036: import org.objectweb.medor.expression.lib.And;
037: import org.objectweb.medor.expression.lib.ConditionalAnd;
038: import org.objectweb.medor.expression.lib.Equal;
039: import org.objectweb.medor.filter.api.FieldOperand;
040: import org.objectweb.medor.query.api.QueryTree;
041: import org.objectweb.medor.query.jorm.api.JormExtent;
042: import org.objectweb.medor.query.jorm.lib.JormQueryTreeHelper;
043: import org.objectweb.medor.type.lib.PTypeSpaceMedor;
044: import org.objectweb.perseus.cache.api.UnFixProtocolException;
045: import org.objectweb.perseus.cache.replacement.api.ReplaceableCacheEntry;
046: import org.objectweb.perseus.persistence.api.StateFilter;
047: import org.objectweb.speedo.api.SpeedoException;
048: import org.objectweb.speedo.mapper.api.JormFactory;
049: import org.objectweb.speedo.mapper.lib.DelegatePMapper;
050: import org.objectweb.speedo.query.api.CompiledQuery;
051: import org.objectweb.speedo.usercache.api.UserCache;
052: import org.objectweb.util.monolog.api.BasicLevel;
053: import org.objectweb.util.monolog.api.Logger;
054:
055: import java.util.Collection;
056: import java.util.Iterator;
057: import java.util.Map;
058:
059: /**
060: * Defines a common abstract implement of CompiledQuery interface. This class
061: * must be subclassed for each Speedo personality.
062: *
063: * @author S.Chassande-Barrioz
064: */
065: public abstract class AbstractCompiledQuery implements CompiledQuery,
066: StateFilter, ReplaceableCacheEntry {
067:
068: /**
069: * status of the Compiledquery
070: * @see CompiledQuery#COMPILED
071: * @see CompiledQuery#DEFINED
072: * @see CompiledQuery#UNDEFINED
073: */
074: protected short status;
075:
076: /**
077: * the classloader used for the loading of persistent class. It is also
078: * used to load generated class such as the XXXMapping (the home of the
079: * persistent class).
080: */
081: protected ClassLoader classLoader;
082:
083: /**
084: * The PNamingContext to use for the parameters.
085: */
086: protected Collection pncParams = null;
087:
088: /**
089: * Logger for monolog
090: */
091: protected Logger logger = null;
092:
093: /**
094: * The delegate mapper initializes a required class if it is not already
095: * done. Otherwise it only foward calls to the real PMapper.
096: */
097: protected DelegatePMapper mapper = null;
098:
099: /**
100: * Is the JormFactory in charge of the initialization of Naming of
101: * persistent class.
102: */
103: protected JormFactory jf;
104:
105: /**
106: * Is the Factory of PrefetchBuffer
107: */
108: protected PrefetchBufferFactory prefetchBufferFactory;
109:
110: /**
111: * A query can correspond to a UserCache.
112: */
113: protected UserCache userCache = null;
114: protected Operand[] userCacheIndexes = null;
115:
116: /**
117: * Compiled queries are cached by Speedo. So a compiled query must be
118: * a ReplaceableCacheEntry. This field defines the old of the query.
119: */
120: protected long age = 0;
121:
122: /**
123: * Compiled queries are cached by Speedo. So a compiled query must be
124: * a ReplaceableCacheEntry. This field defines the number of user of the
125: * query.
126: */
127: protected int fixCount = 0;
128:
129: public PMapper getMapper() {
130: return mapper;
131: }
132:
133: public abstract void setMapper(PMapper m);
134:
135: public void setJormFactory(JormFactory jf) {
136: this .jf = jf;
137: if (mapper != null) {
138: mapper.setJormFactory(jf);
139: }
140: }
141:
142: public Logger getLogger() {
143: return logger;
144: }
145:
146: public PrefetchBufferFactory getPrefetchBufferFactory() {
147: return prefetchBufferFactory;
148: }
149:
150: public void init(Logger l, PMapper m, PrefetchBufferFactory pbf,
151: JormFactory _jf) {
152: logger = l;
153: setMapper(m);
154: setJormFactory(_jf);
155: this .prefetchBufferFactory = pbf;
156: }
157:
158: protected PType getPType(String name) {
159: if ("String".equals(name)) {
160: return PTypeSpace.STRING;
161: }
162: if ("Integer".equals(name)) {
163: return PTypeSpace.OBJINT;
164: }
165: for (int i = 0; i < PTypeSpace.PREDEFINEDPTYPES.length; i++) {
166: PType type = PTypeSpace.PREDEFINEDPTYPES[i];
167: if (type.getJavaName().equals(name)
168: || type.getJormName().equals(name)) {
169: return type;
170: }
171: }
172: if ("Collection".equals(name)
173: || PTypeSpace.COLLECTION.getJavaName().equals(name)) {
174: return PTypeSpace.COLLECTION;
175: }
176: return PTypeSpaceMedor.PNAME;
177: }
178:
179: public short getStatus() {
180: return status;
181: }
182:
183: /**
184: * Assign mappers and project and project name on the JormExtent nodes
185: * include in a QueryTree.
186: * @throws SpeedoException
187: */
188: protected void assignMapper(QueryTree qt) throws SpeedoException {
189: //
190: Collection extents = JormQueryTreeHelper.getJormExtents(qt);
191: boolean debug = logger.isLoggable(BasicLevel.DEBUG);
192: if (debug) {
193: logger.log(BasicLevel.DEBUG, "Extent nodes: "
194: + extents.size());
195: }
196: for (Iterator it = extents.iterator(); it.hasNext();) {
197: JormExtent je = (JormExtent) it.next();
198: try {
199: PClassMapping pcm = jf.getPClassMapping(JormPathHelper
200: .getOriginClass(je.getJormName()), classLoader);
201: if (debug) {
202: logger.log(BasicLevel.DEBUG, "JormExtent: " + je
203: + " / pcm=" + pcm);
204: }
205: je.setPMapper(pcm.getPMapper(), pcm.getProjectName());
206: } catch (PException e) {
207: throw new SpeedoException(
208: "Error while fetching PClassPMapping of the class "
209: + je.getJormName(), e);
210: }
211: }
212: }
213:
214: protected boolean getFieldComparaison(Expression e, Map field2value) {
215: if (e instanceof And || e instanceof ConditionalAnd) {
216: return getFieldComparaison(((Operator) e).getExpression(0),
217: field2value)
218: && getFieldComparaison(((Operator) e)
219: .getExpression(1), field2value);
220: } else if (e instanceof Equal) {
221: Expression tmpe = ((Operator) e).getExpression(0);
222: if (!(tmpe instanceof Operand)) {
223: return false;
224: }
225: Operand op0 = (Operand) tmpe;
226: tmpe = ((Operator) e).getExpression(1);
227: if (!(tmpe instanceof Operand)) {
228: return false;
229: }
230: Operand op1 = (Operand) tmpe;
231: //Equal between two operand
232: if (op0 instanceof FieldOperand) {
233: } else if (op1 instanceof FieldOperand) {
234: //revert if op1 is
235: Operand o = op0;
236: op0 = op1;
237: op1 = o;
238: } else {
239: return false;
240: }
241: //op0 is a field operand
242: if (op1 instanceof FieldOperand) {
243: return false;
244: }
245: // parameter operand or simple operand (constant)
246: String fieldName = ((FieldOperand) op0).getField()
247: .getName();
248: if (fieldName.indexOf('.') != -1) { // short or long navigation path
249: if (fieldName.startsWith("this.")) { //path starts with "this."
250: fieldName = fieldName.substring(5); //remove "this."
251: }
252: if (fieldName.indexOf('.') != -1) { //long navigation path
253: return false;
254: }
255: }
256: field2value.put(fieldName, op1);
257: return true;
258: }
259: return false;
260: }
261:
262: // IMPLEMENTATION OF THE StateFilter INTERFACE //
263: //---------------------------------------------//
264:
265: public boolean accept(org.objectweb.perseus.persistence.api.State ce) {
266: if (logger.isLoggable(BasicLevel.DEBUG)) {
267: logger.log(BasicLevel.DEBUG,
268: "Flush dirty instance of the working state, identifier: "
269: + ce.getCacheEntry().getCeIdentifier());
270: }
271: return true;
272: }
273:
274: // IMPLEMENTATION OF ReplaceableCacheEntry INTERFACE //
275: //---------------------------------------------------//
276: public long getCeAge() {
277: return age;
278: }
279:
280: public void setCeAge(long _age) {
281: this .age = _age;
282: }
283:
284: public void fixCe() {
285: fixCount++;
286: }
287:
288: public void unfixCe() throws UnFixProtocolException {
289: fixCount--;
290: }
291:
292: public int getCeFixCount() {
293: return fixCount;
294: }
295:
296: public Object getCeObject() {
297: return this;
298: }
299: }
|