KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > medor > optim > lib > PushSelectionRule


1 /**
2  * MEDOR: Middleware Enabling Distributed Object Requests
3  *
4  * Copyright (C) 2001-2003 France Telecom R&D
5  * Contact: alexandre.lefebvre@rd.francetelecom.com
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  * Initial developers: M. Alia, S. Chassande-Barrioz, A. Lefebvre
22  */

23
24 package org.objectweb.medor.optim.lib;
25
26 import org.objectweb.medor.api.MedorException;
27 import org.objectweb.medor.expression.api.BinaryOperator;
28 import org.objectweb.medor.expression.api.Expression;
29 import org.objectweb.medor.expression.api.Operator;
30 import org.objectweb.medor.expression.lib.And;
31 import org.objectweb.medor.expression.lib.ConditionalAnd;
32 import org.objectweb.medor.filter.api.FieldOperand;
33 import org.objectweb.medor.query.api.CalculatedField;
34 import org.objectweb.medor.query.api.FilteredQueryTree;
35 import org.objectweb.medor.query.api.PropagatedField;
36 import org.objectweb.medor.query.api.QueryLeaf;
37 import org.objectweb.medor.query.api.QueryNode;
38 import org.objectweb.medor.query.api.QueryTree;
39 import org.objectweb.medor.query.api.QueryTreeField;
40 import org.objectweb.medor.query.lib.Project;
41 import org.objectweb.util.monolog.api.BasicLevel;
42
43 import java.util.HashMap JavaDoc;
44 import java.util.Map JavaDoc;
45
46 /**
47  * This class represents the rule to push selections down a QueryTree.
48  */

49 public class PushSelectionRule extends BasicRule {
50
51     public class SameQT {
52         public boolean isSame;
53         public QueryTree qt;
54
55         public SameQT(boolean i, QueryTree q) {
56             isSame = i;
57             qt = q;
58         }
59         public SameQT() {
60         }
61     }
62
63     public PushSelectionRule() {
64         super("PushSelectionRule");
65     }
66
67     public QueryTree rewrite(QueryTree qt, QueryNode parent) throws MedorException {
68         debug = log != null && log.isLoggable(BasicLevel.DEBUG);
69         rewriteExp(qt, null);
70         return qt;
71     }
72
73     protected void rewriteExp(QueryTree qt, Expression addedExp) throws MedorException {
74         if (debug) log.log(BasicLevel.DEBUG, "****(qt=" + qt + ", addedExp="+ addedExp + ")");
75         if (!(qt instanceof QueryLeaf)) {
76             // treat the FielOperand of the AddedExp to link them to the queryChild
77
addedExp = goDownFieldOperand(addedExp).e;
78         }
79         if (debug) log.log(BasicLevel.DEBUG, "addedExp="+ addedExp);
80
81         FilteredQueryTree fqt = null;
82         ModifiedExpression me = null;
83         if (qt instanceof FilteredQueryTree && qt.getClass()!=Project.class) {
84             fqt = (FilteredQueryTree) qt;
85             //Merge the added exp with the exp of the QueryTree
86
me = merge(fqt.getQueryFilter(), addedExp, 1);
87
88             if (qt instanceof QueryLeaf) {
89                 if (me.isModified)
90                     fqt.setQueryFilter(me.e);
91                 //Do not extract expression for a QueryLeaf because it 's leaf
92
// and the extracted expression could be assign to children of the
93
// leaf
94
return;
95             }
96         }
97         else {
98             me = new ModifiedExpression();
99             me.e = addedExp;
100         }
101
102         Map JavaDoc qt2e = new HashMap JavaDoc();
103         me = extractMapFromExpression(me.e, qt2e, 0);
104         if (debug) log.log(BasicLevel.DEBUG, "me.isModified="+ me.isModified);
105         if (debug) log.log(BasicLevel.DEBUG, "fqt="+ fqt);
106         if (me.isModified && fqt!=null) {
107             // the expression has been modified, some sub expressions has bean
108
// extracted
109
fqt.setQueryFilter(me.e);
110         }
111         QueryTree[] qts = ((QueryNode) qt).getChildren();
112         for (int i=0; i<qts.length; i++) {
113             //Recall the function on the children, with the extracted sub
114
// expression corresponding to the child
115
rewriteExp(qts[i], (Expression) qt2e.get(qts[i]));
116         }
117     }
118
119     /**
120      * It merges an source expresion with an additional expression.
121      * @param origin is the source expression
122      * @param addExp is the additionnal expression which will be merge with the
123      * source.
124      * @return a ModifiedExpression instance. The 'isModified' field indicates
125      * if the source expression has been modified ou replaced. The 'e' field
126      * references the result of the merge.
127      */

128     public ModifiedExpression merge(Expression origin, Expression addExp, int op) {
129         ModifiedExpression result = new ModifiedExpression();
130         if (debug) log.log(BasicLevel.DEBUG, "Merge(" + origin + ", " + addExp + ", " + op + ")");
131         if (addExp == null) {
132             result.e = origin;
133             result.isModified = false;
134         } else if (origin == null) {
135             result.e = addExp;
136             result.isModified = true;
137         } else {
138             if (op == 2)
139                 result.e = new ConditionalAnd(origin, addExp);
140             else
141                 result.e = new And(origin, addExp);
142             result.isModified = true;
143         }
144         return result;
145     }
146
147     /**
148      * This methods does two things. It extracts the expressions which can be
149      * moved to a QueryTree child. The extracted expression are grouped by
150      * QueryTree child in the Map parameter.
151      * @param e is the expression in which sub expression could be extracted
152      * @param qt2e is a map result parameter which must be fill with the
153      * the extractable sub expressions.
154      * @return a modifiedExpression instance. The 'isModified' field indicates
155      * if the source expression has been modified ou replaced. The 'e' field
156      * references the rest of the expression.
157      */

158     public ModifiedExpression extractMapFromExpression(
159             Expression e, Map JavaDoc qt2e, int op) throws MedorException {
160         ModifiedExpression result = new ModifiedExpression();
161         if (debug) log.log(BasicLevel.DEBUG, "extractMapFromExpression(" + e + ")");
162         if (e == null) {
163             result.e = e;
164             result.isModified = false;
165         } else if (e instanceof And || e instanceof ConditionalAnd) {
166             int curOp = (e instanceof And ? 1 : 2);
167             ModifiedExpression l = extractMapFromExpression(
168                     ((BinaryOperator) e).getExpression(0), qt2e, curOp);
169             ModifiedExpression r = extractMapFromExpression(
170                     ((BinaryOperator) e).getExpression(1), qt2e, curOp);
171
172             if (l.e == null) {
173                 //The left expression has been extracted then used the right
174
result.isModified = true;
175                 result.e = r.e;
176             } else if (r.e == null) {
177                 //The right expression has been extracted then used the left
178
result.isModified = true;
179                 result.e = l.e;
180             } else {
181                 //r!=null && l!=null => the reference to the expression does
182
// not change
183
result.e = e;
184                 // By default we suppose that there is no change
185
result.isModified = false;
186                 if (l.isModified) {
187                     // The left has changed => assign the new expression
188
((BinaryOperator) e).setExpression(0, l.e);
189                     result.isModified = true;
190                 }
191                 if (r.isModified) {
192                     // The right has changed => assign the new expression
193
((BinaryOperator) e).setExpression(1, r.e);
194                     result.isModified = true;
195                     result.e = e;
196                 }
197             }
198         } else {
199             // check if the expression is compose by fields which are linked to
200
// to the same QueryTree
201
SameQT sqt = isSameQT(e);
202             if (sqt.isSame) {
203                 // Same QueryTree in the expression
204
if (debug) log.log(BasicLevel.DEBUG, "extractMapFromExpression: same QT: sqt.qt=" + sqt.qt);
205                 ModifiedExpression me = merge((Expression) qt2e.get(sqt.qt), e, op);
206                 qt2e.put(sqt.qt, me.e);
207                 //The current expression can be moved to the queryTree child
208
// then the expression returned is null
209
result.isModified = true;
210                 result.e = null;
211             } else {
212                 if (debug) log.log(BasicLevel.DEBUG, "extractMapFromExpression: not same QT:");
213                 //It is not the same QueryTree in the expression
214
// then it is not possible to move this expression
215
result.isModified = false;
216                 result.e = e;
217             }
218         }
219         return result;
220     }
221
222     /**
223      * It evaluates if inside an expression all QueryTreeField referenced in
224      * FieldOperands come from the same QueryTree.
225      * @param e is the expression in which the FieldOperand field will be
226      * searched
227      * @return a SameQt instance. The 'isSame' field indicates if in the
228      * given expression all Fields are linked to the same QueryTree. If 'isSame'
229      * is true, the 'qt' field is the QueryTree with which all fieldoperand of
230      * expression are linked.
231      */

232     public SameQT isSameQT(Expression e) throws MedorException {
233         if (debug) log.log(BasicLevel.DEBUG, "isSameQT(" + e +")");
234         if (e instanceof Operator) {
235             Operator op = (Operator) e;
236             SameQT res = new SameQT();
237             res.isSame = true;
238             SameQT c = null;
239             for (int i=0; i<op.getOperandNumber() && res.isSame; i++) {
240                 c = isSameQT(((Operator) e).getExpression(i));
241                 if (debug) log.log(BasicLevel.DEBUG, "isSameQT(): c.isSame=" + c.isSame);
242                 if (debug) log.log(BasicLevel.DEBUG, "isSameQT(): c.qt=" + c.qt);
243                 res.isSame &= c.isSame;
244                 if (res.qt == null) {
245                     res.qt = c.qt;
246                 } else if (c.qt != null)
247                     res.isSame &= (c.qt == res.qt);
248             }
249             return res;
250         } else if (e instanceof FieldOperand) {
251             QueryTree qtChild = ((QueryTreeField) ((FieldOperand) e).getField())
252                     .getQueryTree();
253             return new SameQT(true, qtChild);
254         } else {
255             return new SameQT(true, null);
256         }
257     }
258
259     public ModifiedExpression goDownFieldOperand(Expression e)
260             throws MedorException {
261         ModifiedExpression me = new ModifiedExpression();
262         me.e = e;
263         me.isModified = false;
264         if (e instanceof Operator) {
265             if (debug) log.log(BasicLevel.DEBUG, "Operator " + e);
266             Operator op = (Operator) e;
267             for (int i=0; i<op.getOperandNumber(); i++) {
268                 me = goDownFieldOperand(op.getExpression(i));
269                 if (me.isModified)
270                     op.setExpression(i, me.e);
271             }
272             // but the current expression does not change
273
me.e = e;
274             me.isModified = false;
275         } else if (e instanceof FieldOperand) {
276             if (debug) log.log(BasicLevel.DEBUG, "FieldOperand " + e);
277             FieldOperand fo = (FieldOperand) e;
278             QueryTreeField f = (QueryTreeField) fo.getField();
279             if (f.getQueryTree() instanceof QueryLeaf) {
280                 if (debug) log.log(BasicLevel.DEBUG, "FieldOperand QueryLeaf");
281                 // On a QueryLeaf the FieldOperand references Field of the same
282
// QueryTree and not a Field of a QueryTree child.
283
//me.e = e;
284
//me.isModified = false;
285
} else if (f instanceof PropagatedField) {
286                 if (debug) log.log(BasicLevel.DEBUG, "FieldOperand PropagatedField " + f);
287                 //assign the field of child to the PropagatedField
288
fo.setField(((PropagatedField) f).getPreviousFields()[0]);
289                 //me.e = e;
290
//me.isModified = false;
291
} else if (f instanceof CalculatedField) {
292                 if (debug) log.log(BasicLevel.DEBUG, "FieldOperand CalculatedField" + f);
293                 //replace the CalculatedField by its value
294
me.e = ((CalculatedField) e).getExpression();
295                 me.isModified = true;
296             } else
297                 throw new MedorException("Impossible move other type:" + f);
298         }
299         return me;
300     }
301 }
Popular Tags