/**
* Speedo: an implementation of JDO compliant personality on top of JORM generic
* I/O sub-system.
* Copyright (C) 2001-2006 France Telecom
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact: speedo@objectweb.org
*
* Authors: S. Chassande-Barrioz
*
*/
package org.objectweb.speedo.query.lib;
import org.objectweb.jorm.api.PClassMapping;
import org.objectweb.jorm.api.PException;
import org.objectweb.jorm.api.PMapper;
import org.objectweb.jorm.lib.JormPathHelper;
import org.objectweb.jorm.type.api.PType;
import org.objectweb.jorm.type.api.PTypeSpace;
import org.objectweb.medor.eval.prefetch.api.PrefetchBufferFactory;
import org.objectweb.medor.expression.api.Expression;
import org.objectweb.medor.expression.api.Operand;
import org.objectweb.medor.expression.api.Operator;
import org.objectweb.medor.expression.lib.And;
import org.objectweb.medor.expression.lib.ConditionalAnd;
import org.objectweb.medor.expression.lib.Equal;
import org.objectweb.medor.filter.api.FieldOperand;
import org.objectweb.medor.query.api.QueryTree;
import org.objectweb.medor.query.jorm.api.JormExtent;
import org.objectweb.medor.query.jorm.lib.JormQueryTreeHelper;
import org.objectweb.medor.type.lib.PTypeSpaceMedor;
import org.objectweb.perseus.cache.api.UnFixProtocolException;
import org.objectweb.perseus.cache.replacement.api.ReplaceableCacheEntry;
import org.objectweb.perseus.persistence.api.StateFilter;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.mapper.api.JormFactory;
import org.objectweb.speedo.mapper.lib.DelegatePMapper;
import org.objectweb.speedo.query.api.CompiledQuery;
import org.objectweb.speedo.usercache.api.UserCache;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
/**
* Defines a common abstract implement of CompiledQuery interface. This class
* must be subclassed for each Speedo personality.
*
* @author S.Chassande-Barrioz
*/
public abstract class AbstractCompiledQuery
implements CompiledQuery, StateFilter, ReplaceableCacheEntry {
/**
* status of the Compiledquery
* @see CompiledQuery#COMPILED
* @see CompiledQuery#DEFINED
* @see CompiledQuery#UNDEFINED
*/
protected short status;
/**
* the classloader used for the loading of persistent class. It is also
* used to load generated class such as the XXXMapping (the home of the
* persistent class).
*/
protected ClassLoader classLoader;
/**
* The PNamingContext to use for the parameters.
*/
protected Collection pncParams = null;
/**
* Logger for monolog
*/
protected Logger logger = null;
/**
* The delegate mapper initializes a required class if it is not already
* done. Otherwise it only foward calls to the real PMapper.
*/
protected DelegatePMapper mapper = null;
/**
* Is the JormFactory in charge of the initialization of Naming of
* persistent class.
*/
protected JormFactory jf;
/**
* Is the Factory of PrefetchBuffer
*/
protected PrefetchBufferFactory prefetchBufferFactory;
/**
* A query can correspond to a UserCache.
*/
protected UserCache userCache = null;
protected Operand[] userCacheIndexes = null;
/**
* Compiled queries are cached by Speedo. So a compiled query must be
* a ReplaceableCacheEntry. This field defines the old of the query.
*/
protected long age = 0;
/**
* Compiled queries are cached by Speedo. So a compiled query must be
* a ReplaceableCacheEntry. This field defines the number of user of the
* query.
*/
protected int fixCount = 0;
public PMapper getMapper() {
return mapper;
}
public abstract void setMapper(PMapper m);
public void setJormFactory(JormFactory jf) {
this.jf = jf;
if (mapper != null) {
mapper.setJormFactory(jf);
}
}
public Logger getLogger() {
return logger;
}
public PrefetchBufferFactory getPrefetchBufferFactory() {
return prefetchBufferFactory;
}
public void init(Logger l,
PMapper m,
PrefetchBufferFactory pbf,
JormFactory _jf) {
logger = l;
setMapper(m);
setJormFactory(_jf);
this.prefetchBufferFactory = pbf;
}
protected PType getPType(String name) {
if ("String".equals(name)) {
return PTypeSpace.STRING;
}
if ("Integer".equals(name)) {
return PTypeSpace.OBJINT;
}
for (int i = 0; i < PTypeSpace.PREDEFINEDPTYPES.length; i++) {
PType type = PTypeSpace.PREDEFINEDPTYPES[i];
if (type.getJavaName().equals(name)
|| type.getJormName().equals(name)) {
return type;
}
}
if ("Collection".equals(name)
|| PTypeSpace.COLLECTION.getJavaName().equals(name)) {
return PTypeSpace.COLLECTION;
}
return PTypeSpaceMedor.PNAME;
}
public short getStatus() {
return status;
}
/**
* Assign mappers and project and project name on the JormExtent nodes
* include in a QueryTree.
* @throws SpeedoException
*/
protected void assignMapper(QueryTree qt) throws SpeedoException {
//
Collection extents = JormQueryTreeHelper.getJormExtents(qt);
boolean debug = logger.isLoggable(BasicLevel.DEBUG);
if (debug) {
logger.log(BasicLevel.DEBUG, "Extent nodes: " + extents.size());
}
for (Iterator it = extents.iterator(); it.hasNext();) {
JormExtent je = (JormExtent) it.next();
try {
PClassMapping pcm = jf.getPClassMapping(
JormPathHelper.getOriginClass(je.getJormName()),
classLoader);
if (debug) {
logger.log(BasicLevel.DEBUG,
"JormExtent: " + je + " / pcm=" + pcm);
}
je.setPMapper(pcm.getPMapper(), pcm.getProjectName());
} catch (PException e) {
throw new SpeedoException(
"Error while fetching PClassPMapping of the class "
+ je.getJormName(), e);
}
}
}
protected boolean getFieldComparaison(Expression e, Map field2value) {
if (e instanceof And || e instanceof ConditionalAnd) {
return getFieldComparaison(((Operator) e).getExpression(0), field2value)
&& getFieldComparaison(((Operator) e).getExpression(1), field2value);
} else if (e instanceof Equal){
Expression tmpe = ((Operator) e).getExpression(0);
if (!(tmpe instanceof Operand)) {
return false;
}
Operand op0 = (Operand) tmpe;
tmpe = ((Operator) e).getExpression(1);
if (!(tmpe instanceof Operand)) {
return false;
}
Operand op1 = (Operand) tmpe;
//Equal between two operand
if (op0 instanceof FieldOperand) {
} else if (op1 instanceof FieldOperand) {
//revert if op1 is
Operand o = op0;
op0 = op1;
op1 = o;
} else {
return false;
}
//op0 is a field operand
if (op1 instanceof FieldOperand) {
return false;
}
// parameter operand or simple operand (constant)
String fieldName = ((FieldOperand) op0).getField().getName();
if (fieldName.indexOf('.') != -1) { // short or long navigation path
if (fieldName.startsWith("this.")) { //path starts with "this."
fieldName = fieldName.substring(5); //remove "this."
}
if (fieldName.indexOf('.') != -1) { //long navigation path
return false;
}
}
field2value.put(fieldName, op1);
return true;
}
return false;
}
// IMPLEMENTATION OF THE StateFilter INTERFACE //
//---------------------------------------------//
public boolean accept(org.objectweb.perseus.persistence.api.State ce) {
if (logger.isLoggable(BasicLevel.DEBUG)) {
logger.log(BasicLevel.DEBUG,
"Flush dirty instance of the working state, identifier: "
+ ce.getCacheEntry().getCeIdentifier());
}
return true;
}
// IMPLEMENTATION OF ReplaceableCacheEntry INTERFACE //
//---------------------------------------------------//
public long getCeAge() {
return age;
}
public void setCeAge(long _age) {
this.age = _age;
}
public void fixCe() {
fixCount++;
}
public void unfixCe() throws UnFixProtocolException {
fixCount--;
}
public int getCeFixCount() {
return fixCount;
}
public Object getCeObject() {
return this;
}
}