001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999 Bull S.A.
004: * Contact: jonas-team@objectweb.org
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.1 of the License, or 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
019: * USA
020: *
021: * Initial developer(s):
022: * Contributor(s):
023: *
024: * --------------------------------------------------------------------------
025: * $Id: MedorFactory.java 6673 2005-04-28 16:53:00Z benoitf $
026: * --------------------------------------------------------------------------
027: */package org.objectweb.jonas_ejb.container.jorm;
028:
029: import java.util.ArrayList;
030: import java.util.HashMap;
031: import java.util.Map;
032:
033: import javax.ejb.EJBException;
034:
035: import org.objectweb.jonas_ejb.container.JContainer;
036: import org.objectweb.jonas_ejb.container.TraceEjb;
037: import org.objectweb.jonas_ejb.deployment.api.DeploymentDescEjb2;
038: import org.objectweb.jonas_ejb.deployment.api.EntityCmp2Desc;
039: import org.objectweb.jonas_ejb.deployment.api.EntityDesc;
040: import org.objectweb.jonas_ejb.deployment.api.MethodCmp2Desc;
041: import org.objectweb.jonas_ejb.lib.EjbqlLimiterRange;
042: import org.objectweb.jonas_ejb.lib.EjbqlQueryTreeHolder;
043: import org.objectweb.jonas_lib.deployment.api.DeploymentDescException;
044: import org.objectweb.jorm.metainfo.api.Manager;
045: import org.objectweb.medor.api.EvaluationException;
046: import org.objectweb.medor.api.MedorException;
047: import org.objectweb.medor.eval.api.ConnectionResources;
048: import org.objectweb.medor.eval.api.QueryEvaluator;
049: import org.objectweb.medor.eval.lib.BasicEvaluationMetaData;
050: import org.objectweb.medor.eval.prefetch.api.PrefetchBuffer;
051: import org.objectweb.medor.eval.prefetch.lib.PrefetchBufferFactoryImpl;
052: import org.objectweb.medor.expression.api.ParameterOperand;
053: import org.objectweb.medor.expression.api.TypingException;
054: import org.objectweb.medor.lib.Log;
055: import org.objectweb.medor.optim.api.ExecPlanGenerator;
056: import org.objectweb.medor.optim.api.QueryTransformer;
057: import org.objectweb.medor.optim.jorm.Jorm2Rdb;
058: import org.objectweb.medor.optim.lib.BasicQueryRewriter;
059: import org.objectweb.medor.optim.lib.FlattenQueryTreeRule;
060: import org.objectweb.medor.optim.lib.IndexesGenerator;
061: import org.objectweb.medor.query.api.QueryLeaf;
062: import org.objectweb.medor.query.api.QueryTree;
063: import org.objectweb.medor.tuple.api.TupleCollection;
064: import org.objectweb.util.monolog.api.BasicLevel;
065:
066: /**
067: * This class does the initialisation of Medor and permits to access to the
068: * query. The optimisation of the query tree is done during the first time that
069: * it is used.
070: * @author S.Chassande-Barrioz
071: */
072: public abstract class MedorFactory extends JormFactory {
073:
074: /**
075: * This field references the query transformer which must be used to
076: * optimize the medor requests.
077: */
078: protected QueryTransformer queryTransformer = null;
079:
080: protected Manager miManager = null;
081:
082: protected ExecPlanGenerator indexesGenerator;
083:
084: protected boolean optimizeAtInit = false;
085:
086: /**
087: * This is the prefetch index for the query method CURRENTLY evaluated
088: */
089: private int prefetchIndex;
090:
091: /**
092: * Limiter ranges for the query method CURRENTLY evaluated
093: */
094: private EjbqlLimiterRange[] limiterRanges = null;
095:
096: public MedorFactory() {
097: super ();
098: if (Log.loggerFactory != TraceEjb.loggerFactory) {
099: Log.loggerFactory = TraceEjb.loggerFactory;
100: }
101: }
102:
103: /**
104: * It retrieves a medor request which is evaluable and optimized. The method
105: * index is translate into a request index, then the found request is
106: * optimized if it is not already.
107: * @param methodDesc is the MethodCmp2Desc of the finder or select method.
108: * @return the QueryTree optimized which is associated to the method index
109: */
110: public synchronized QueryEvaluator getOptimizedRequest(
111: MethodCmp2Desc methodDesc) throws MedorException {
112: if (TraceEjb.isVerbose()) {
113: TraceEjb.logger.log(BasicLevel.DEBUG,
114: "getOptimizedRequest(method name: "
115: + methodDesc.getMethod().getName() + ")");
116: }
117: try {
118: EjbqlQueryTreeHolder qth = methodDesc
119: .getQueryTreeHolder(mapper);
120: // set the prefetch index for this method
121: setPrefetchIndex(qth.getPrefetchIndex());
122: // set the optimizer if not set yet
123: if (qth.getQueryOptimizer() == null) {
124: if (queryTransformer == null) {
125: ArrayList rules = new ArrayList(2);
126: rules.add(new FlattenQueryTreeRule());
127: rules.add(new Jorm2Rdb());
128: queryTransformer = new BasicQueryRewriter(rules);
129: }
130: qth.setQueryOptimizer(new QueryTransformer() {
131:
132: public QueryTree transform(QueryTree qt)
133: throws MedorException {
134: QueryTree qt1 = queryTransformer.transform(qt);
135: //TraceEjb.query.log(BasicLevel.DEBUG, "Transformed
136: // QueryTree: ");
137: //QueryTreePrinter.printQueryTree(qt1, TraceEjb.query,
138: // BasicLevel.DEBUG);
139: if (indexesGenerator == null) {
140: throw new Error(
141: "getOptimizedRequest: indexesGenerator == null");
142: }
143: return indexesGenerator.transform(qt1);
144: }
145: });
146: }
147: limiterRanges = qth.getLimiterRanges();
148: return qth.getOptimizedQueryTree();
149: } catch (Exception e) {
150: throw new MedorException(
151: "Impossible to optimize the query "
152: + methodDesc.getQuery(), e);
153: }
154: }
155:
156: /**
157: * It optimized all medor requests which are already not.
158: */
159: /*
160: * NO MORE USED ??? public void optimizeAll() throws MedorException { for
161: * (Iterator it = dd.getMethodDescIterator(); it.hasNext();) {
162: * MethodCmp2Desc mcd = (MethodCmp2Desc) it.next(); if
163: * (!mcd.isFindByPrimaryKey() && (mcd.isFinder() || mcd.isEjbSelect())) {
164: * getOptimizedRequest(mcd.getIndex()); } } }
165: */
166:
167: /**
168: * It evaluate an optimized medor request according to the specified
169: * parameters To evalute the medor request the query evaluator is used.
170: * @param conn is the connection handle
171: * @param methodIndex is method index which permits to find a medor request.
172: * @param parameters is the parameters (key=parameter name / value=parameter
173: * value)
174: * @return TupleCollection is the result of the request
175: */
176: public TupleCollection evaluate(Object conn, int methodIndex,
177: ParameterOperand[] parameters) throws MedorException {
178:
179: MethodCmp2Desc mcd = (MethodCmp2Desc) dd
180: .getMethodDesc(methodIndex);
181: QueryEvaluator evaluator = getOptimizedRequest(mcd);
182:
183: // Calculates and gets the required connection resources for this query
184: ConnectionResources cr = evaluator
185: .getRequiredConnectionResources();
186:
187: // Gets the QueryLeafs that requierd connections
188: QueryLeaf[] leaves = cr.getRequiredQueryLeafConnection();
189:
190: // Setting QueryLeaf's appropriated connection Object
191: // TODO : All jorm classes are not mapped on the same mapper
192: // than the current class - should use connections from different
193: // datasources.
194: if (conn == null) {
195: throw new MedorException("invalid connection handle [null]");
196: }
197: for (int i = 0; (i < leaves.length); i++) {
198: cr.setConnection(leaves[i], conn);
199: }
200: // PrefetchBuffer initialization if prefetch tag setting
201: PrefetchBuffer prefetchBuffer = null;
202: if (mcd.getPrefetch()) {
203: Object tx = null;
204: try {
205: tx = this .getTransactionManager().getTransaction();
206: if (tx != null) {
207: prefetchBuffer = mapper.getPrefetchCache()
208: .createPrefetchBuffer(
209: new PrefetchBufferFactoryImpl(),
210: this , tx, getPrefetchIndex(), true);
211: }
212: } catch (javax.transaction.SystemException e) {
213: // TODO : Que fait-on ???
214: TraceEjb.logger
215: .log(
216: BasicLevel.ERROR,
217: "Cannot get the current transaction to create the Prefetch buffer:",
218: e);
219: }
220: }
221: // Map of EvaluationMetaData initialization needed for LIMIT clause
222: Map evalMDMap = null;
223: if (limiterRanges.length > 0) {
224: try {
225: // There is a LIMIT clause, init the Map of EvaluationMetaData
226: evalMDMap = new HashMap();
227: BasicEvaluationMetaData evalMD = new BasicEvaluationMetaData();
228: EjbqlLimiterRange range = limiterRanges[0];
229: if (range.getKind() == EjbqlLimiterRange.KIND_PARAMETER) {
230: evalMD.setLimitedRangeStartAt(parameters[range
231: .getValue()].getInt());
232: } else {
233: evalMD.setLimitedRangeStartAt(range.getValue());
234: }
235: if (TraceEjb.isDebugQuery()) {
236: TraceEjb.query.log(BasicLevel.LEVEL_DEBUG,
237: "Query with LIMITer Range Start At = "
238: + evalMD.getLimitedRangeStartAt()
239: + " for method name "
240: + mcd.getMethod().getName());
241: }
242: if (limiterRanges.length > 1) {
243: range = limiterRanges[1];
244: if (range.getKind() == EjbqlLimiterRange.KIND_PARAMETER) {
245: System.out
246: .println("parameters[range.getValue()].getInt() = "
247: + parameters[range.getValue()]
248: .getInt());
249: evalMD.setLimitedRangeSize(parameters[range
250: .getValue()].getInt());
251: } else {
252: evalMD.setLimitedRangeSize(range.getValue());
253: }
254: if (TraceEjb.isDebugQuery()) {
255: TraceEjb.query.log(BasicLevel.LEVEL_DEBUG,
256: "Query with LIMITer Range Size = "
257: + evalMD.getLimitedRangeSize()
258: + " for method name "
259: + mcd.getMethod().getName());
260: }
261: }
262: evalMDMap.put(leaves[0], evalMD);
263: } catch (TypingException te) {
264: throw new MedorException(
265: "Invalid parameter for a LIMIT range", te);
266: }
267: }
268: try {
269: return evaluator.evaluate(parameters, cr, prefetchBuffer,
270: evalMDMap);
271: } catch (EvaluationException e) {
272: throw e;
273: }
274: }
275:
276: public void init(EntityDesc ed, JContainer c, String mapperName) {
277: super .init(ed, c, mapperName);
278:
279: ecd = (EntityCmp2Desc) ed;
280:
281: //------------------- JORM META INFORMATION BUILDING ----------------//
282: if (TraceEjb.isVerbose()) {
283: TraceEjb.logger.log(BasicLevel.DEBUG,
284: "Jorm Meta information building");
285: }
286: DeploymentDescEjb2 dd = ecd.getDeploymentDescEjb2();
287: try {
288: miManager = dd.getJormManager();
289: } catch (DeploymentDescException e) {
290: TraceEjb.logger
291: .log(
292: BasicLevel.ERROR,
293: "impossible to load the jorm meta information into the manager",
294: e);
295: throw new EJBException(
296: "impossible to load the jorm meta information into the manager",
297: e);
298: }
299:
300: //---------------------- MEDOR INITIALIZATION -----------------------//
301: if (TraceEjb.isVerbose()) {
302: TraceEjb.logger.log(BasicLevel.DEBUG,
303: "Medor initialisation");
304: }
305: indexesGenerator = new IndexesGenerator();
306:
307: }
308:
309: private void setPrefetchIndex(int i) {
310: prefetchIndex = i;
311: }
312:
313: private int getPrefetchIndex() {
314: return prefetchIndex;
315: }
316:
317: }
|