KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > medor > query > jorm > lib > NavigatorNodeFactory


1 /**
2  * MEDOR: Middleware Enabling Distributed Object Requests
3  *
4  * Copyright (C) 2001-2004 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, A. Lefebvre, S. Chassande-Barrioz
22  */

23
24 package org.objectweb.medor.query.jorm.lib;
25
26 import java.util.ArrayList JavaDoc;
27 import java.util.Collections JavaDoc;
28
29 import org.objectweb.jorm.metainfo.api.Class;
30 import org.objectweb.jorm.metainfo.api.ClassRef;
31 import org.objectweb.jorm.metainfo.api.GenClassRef;
32 import org.objectweb.jorm.metainfo.api.Reference;
33 import org.objectweb.jorm.metainfo.api.TypedElement;
34 import org.objectweb.medor.api.Field;
35 import org.objectweb.medor.api.MedorException;
36 import org.objectweb.medor.api.TupleStructure;
37 import org.objectweb.medor.expression.api.Expression;
38 import org.objectweb.medor.expression.api.MalformedExpressionException;
39 import org.objectweb.medor.expression.api.Operand;
40 import org.objectweb.medor.expression.api.TypingException;
41 import org.objectweb.medor.expression.lib.And;
42 import org.objectweb.medor.expression.lib.Equal;
43 import org.objectweb.medor.expression.lib.Not;
44 import org.objectweb.medor.filter.api.FieldOperand;
45 import org.objectweb.medor.filter.jorm.lib.NavigatorOperator;
46 import org.objectweb.medor.filter.lib.BasicFieldOperand;
47 import org.objectweb.medor.filter.lib.ExpressionPrinter;
48 import org.objectweb.medor.filter.lib.MemberOf;
49 import org.objectweb.medor.lib.Log;
50 import org.objectweb.medor.query.api.PropagatedField;
51 import org.objectweb.medor.query.api.QueryNode;
52 import org.objectweb.medor.query.api.QueryTree;
53 import org.objectweb.medor.query.api.QueryTreeField;
54 import org.objectweb.medor.query.jorm.api.JormExtent;
55 import org.objectweb.medor.query.lib.JoinProject;
56 import org.objectweb.medor.query.lib.QueryTreePrinter;
57 import org.objectweb.util.monolog.api.BasicLevel;
58 import org.objectweb.util.monolog.api.Logger;
59
60 /**
61  * This class constructs a QueryTree from a NavigatorOperator, which represents
62  * a path expression.
63  * <p>It is a factory for normal JoinProject query nodes, which implement the
64  * semantics of the path traversal represented by the NavigatorOperator.
65  */

66 public class NavigatorNodeFactory {
67
68     public final static String JavaDoc PNAME_FIELD_NAME = "object";
69     private static int pnameFieldNameIndex = 0;
70
71     public final static String JavaDoc GENCLASS_ELEMENT_NAME = "element";
72
73     /**
74      * To navigate up to the last field.
75      */

76     public final static byte NAVIGATION = 1;
77     /**
78      * To navigate up to the element referenced by the last field.
79      * <p>For a GenClassRef, includes the GenClass element. For a ClassRef,
80      * includes all fields of the referenced class object.
81      */

82     public final static byte NAVIGATION_INTO_LAST = 2;
83
84     /**
85      * Applies to navigation ending with a GenClassRef only.
86      * <p> Tests whether there are no GenClass elements for the GenClassRef.
87      */

88     public final static byte IS_EMPTY = 4;
89     /**
90      * Applies to navigation ending with a GenClassRef only.
91      * <p> Tests whether there are GenClass elements for the GenClassRef.
92      */

93     public final static byte IS_NOT_EMPTY = 8;
94
95     public static Logger logger = Log.getLoggerFactory()
96             .getLogger("org.objectweb.medor.query.jorm.NavigatorNodeFactory");
97
98     /**
99      * Creates a QueryTree corresponding to the path traversal represented by
100      * the NavigatorOperator.
101      * <p>The end of the path expression can either be a single-valued field or
102      * a reference to a GenClass. In the latter case, the elements
103      * of the GenClass are projected together with their index attributes.
104      * @param nav is the NavigatorOperator representing the path expression.
105      * This operator starts with a FieldOperand pointing to a Field called here
106      * FStart. All fields in the node hosting FStart are projected.
107      * @param aliasName is the root name of the Fields reached by the path
108      * expression.
109      * @param operation indicates which operation to perform (NAVIGATION,
110      * NAVIGATION_INTO_LAST, IS_EMPTY or IS_NOT_EMPTY)
111      * @return the QueryTreeField which matches the NavigatorOperator.
112      */

113     public static QueryTreeField navigate(NavigatorOperator nav,
114                                           String JavaDoc aliasName,
115                                           byte operation)
116             throws MedorException {
117         //'qtf' is the QueryTreeField to use for a join
118
QueryTreeField qtf = null;
119         //pnf is the PNameField which must be used to access to the meta info
120
PNameField pnf = null;
121         //op is the operation type at each step
122
byte op = NAVIGATION;
123         boolean joinAlreadyConstructed = false;
124         String JavaDoc fieldName = null;
125         try {
126             fieldName = ((Operand) nav.getExpression(1)).getString();
127         } catch (TypingException te) {
128             throw new MedorException(te);
129         }
130         logger.log(BasicLevel.DEBUG, "navigate(" + aliasName + ", "
131                 + ExpressionPrinter.e2str(nav.getExpression(0)) + ", " + fieldName
132                 + ", op:" + op + ")");
133
134         //iterate over the navigation path, starting with the FieldOperand
135
ArrayList JavaDoc path = new ArrayList JavaDoc();
136         path.add(nav.getFieldOperand());
137         path = nav.getPath(path);
138
139         for (int j = 0; j < path.size() - 1; j++) {
140
141             boolean propagQtf;
142             //restores the type of operation to the inital one for the end
143
//of the navigation
144
if (j == path.size() - 2) {
145                 op = operation;
146             }
147             Object JavaDoc element = path.get(j);
148             if (element instanceof FieldOperand) {
149                 qtf = (QueryTreeField) ((FieldOperand) element).getField();
150                 pnf = getPNameField(qtf);
151                 logger.log(BasicLevel.DEBUG, "Navigation from FieldOperand " + qtf.getName());
152                 propagQtf = true;
153             } else {
154                 //propagQtf = false;
155
//adding even intermediate fields
156
propagQtf = true;
157                 logger.log(BasicLevel.DEBUG, "Further navigation for " + element);
158                 //The alias name is null because only the first element (the last
159
//join) can be have an alias
160
}
161
162             fieldName = (String JavaDoc) path.get(j + 1);
163             logger.log(BasicLevel.DEBUG, "Navigate to " + fieldName);
164
165             logger.log(BasicLevel.DEBUG, "propagQtf=" + propagQtf);
166             logger.log(BasicLevel.DEBUG, "qtf=" + qtf.getName() + " of node " + qtf.getQueryTree());
167             if (pnf == null)
168                 throw new MedorException("Impossible to find a PNameField");
169
170             // 'qt' is the QueryTree of 'qtf"
171
QueryTree qt = qtf.getQueryTree();
172
173             if (!pnf.isClassPName()) {
174                 logger.log(BasicLevel.DEBUG, "Reference from a Class to a Class");
175                 Reference ref = pnf.getReference();
176
177                 Class JavaDoc jormClass = null;
178                 if (ref instanceof ClassRef)
179                     jormClass = ((ClassRef) ref).getMOClass();
180                 else
181                     throw new MedorException("Impossible to navigate with PName:"
182                             + ref.getName() + " " + ref.getParent());
183
184                 ClassExtent extent = null;
185                 String JavaDoc nodeName;
186                 if (j == path.size() - 2) {
187                     //this is the end of the navigation
188
logger.log(BasicLevel.DEBUG, "Extent at the end of the navigation");
189                     nodeName = (op != NAVIGATION_INTO_LAST
190                             ? aliasName
191                             : jormClass.getFQName());
192                     pnameFieldNameIndex += 1;
193                     //create the extent corresponding to the reference
194
extent = new ClassExtent(
195                             jormClass,
196                             nodeName,
197                             PNAME_FIELD_NAME + pnameFieldNameIndex,
198                             false);
199                 } else {
200                     //in the middle of the navigation: propagate only the required
201
//field
202
logger.log(BasicLevel.DEBUG, "Extent in the middle of the navigation");
203                     nodeName = jormClass.getFQName();
204                     pnameFieldNameIndex += 1;
205                     //create the extent corresponding to the reference
206
extent = new ClassExtent(
207                             jormClass,
208                             nodeName,
209                             new String JavaDoc[]{fieldName},
210                             true,
211                             PNAME_FIELD_NAME + pnameFieldNameIndex);
212                 }
213                 // pnf references the PNameField of the joined extent
214
pnf = (PNameField) extent.getField(extent.getPNameFieldName());
215
216                 JoinProject join;
217                 if (!joinAlreadyConstructed) {
218                     logger.log(BasicLevel.DEBUG, "Constructing new JoinProject");
219                     join = new JoinProject("", op != NAVIGATION);
220                     joinAlreadyConstructed = true;
221                     //add the join condition: pnf should be equal to the
222
//PName of the extent
223
join.setQueryFilter(
224                             new Equal(
225                                     new BasicFieldOperand(qtf),
226                                     new BasicFieldOperand(pnf)
227                             )
228                     );
229                 } else {
230                     join = (JoinProject) qtf.getQueryTree();
231                     logger.log(BasicLevel.DEBUG, "Re-using JoinProject " + join);
232                     propagQtf = false;
233                     //add the join condition: pnf should be equal to the
234
//PName of the extent
235
join.setQueryFilter(
236                             new And(
237                                 new Equal(
238                                     new BasicFieldOperand(
239                                             ((PropagatedField)qtf).getPreviousFields()[0]),
240                                     new BasicFieldOperand(pnf)
241                                 ),
242                                 join.getQueryFilter()
243                         )
244                     );
245                 }
246
247                 logger.log(BasicLevel.DEBUG, "Current qt is:");
248                 QueryTreePrinter.printQueryTree(qt, logger);
249                 logger.log(BasicLevel.DEBUG, "Current join is:");
250                 QueryTreePrinter.printQueryTree(join, logger);
251
252                 //project in qt all fields of the QueryTree containing
253
//the origin of the path expression
254
Field[] fToAdd = qt.getTupleStructure().getFields();
255                 logger.log(BasicLevel.DEBUG, "Adding fields:");
256                 logger.log(BasicLevel.DEBUG, "qtf is:" + qtf);
257                 for (int i = 0; i < fToAdd.length; i++) {
258                     if (propagQtf || qtf != fToAdd[i]) {
259                         logger.log(BasicLevel.DEBUG, "\t-" + fToAdd[i].getName());
260                         //propagate fields only if not already there
261
try {
262                             join.getField(fToAdd[i].getName());
263                             logger.log(BasicLevel.DEBUG, "Field already present: not adding.");
264
265                         } catch (MedorException e) {
266                             logger.log(BasicLevel.DEBUG, "Field not present: adding.");
267
268                             join.addPropagatedField(
269                                 fToAdd[i].getName(),
270                                 fToAdd[i].getType(),
271                                 new QueryTreeField[]{(QueryTreeField) fToAdd[i]});
272                         }
273                     }
274                     //else
275
//logger.log(BasicLevel.DEBUG, "\t-Do not propagate " + fToAdd[i].getName());
276
}
277
278                 // project in qt the fields corresponding to the end of the path
279
// expression
280
//TODO add only of end of navigation
281
fToAdd = extent.getTupleStructure().getFields();
282                 for (int i = 0; i < fToAdd.length; i++) {
283                     logger.log(BasicLevel.DEBUG, "Adding propagated field " + fToAdd[i].getName());
284                     join.addPropagatedField(
285                             fToAdd[i].getName(),
286                             fToAdd[i].getType(),
287                             new QueryTreeField[]{(QueryTreeField) fToAdd[i]});
288                 }
289                 qtf = (QueryTreeField)
290                         join.getField(extent.getFieldName(nodeName, fieldName));
291                 //qtf references a propagated field to a field named 'fieldName'
292

293                 qt = join;
294             } else { //it is a class PName
295
logger.log(BasicLevel.DEBUG, "Adding the field if not already present");
296                 if (pnf.isInGenClass()) {
297                     throw new MedorException(
298                             "Impossible to navigate with a multi valued reference");
299                 }
300                 logger.log(BasicLevel.DEBUG, "Checking that " + fieldName + " appears in " + qt);
301                 // The field 'fieldName' must be found on 'qt'
302
String JavaDoc fn = contains(qt.getTupleStructure(),
303                         pnf.getQueryTree().getName() + "." + fieldName);
304                 if (fn != null) {
305                     qtf = (QueryTreeField) qt.getTupleStructure().getField(fn);
306                 } else if (qt instanceof ClassExtent) {
307                     //In case where qt is a ClassExtent
308
ClassExtent extent = (ClassExtent) qt;
309                     TypedElement te =
310                             ((Class JavaDoc) extent.getMetaObject()).getTypedElement(fieldName);
311                     if (te == null)
312                         throw new MedorException("The jorm class "
313                                 + ((Class JavaDoc) extent.getMetaObject()).getName()
314                                 + " does not provide a field " + fieldName);
315                     qtf = extent.addField(te);
316                 } else
317                     throw new MedorException(
318                             "No field " + fieldName + " found on the query tree " + qt);
319             }
320             logger.log(BasicLevel.DEBUG, "Query tree before the end of treatment:");
321             QueryTreePrinter.printQueryTree(qt, logger);
322             qtf = endOfNavigation(op, qtf, qt, aliasName);
323             pnf = getPNameField(qtf);
324         }
325         return qtf;
326     }
327
328
329     /**
330      * Manages the end of the navigation in the case of a reference
331      * @param op is the navigation operation type
332      * @param qtf is the QueryTreeField
333      * @param qt the QueryTree
334      * @param aliasName the alias name of the QueryTree
335      * @return the QueryTreeField corresponding to the end of the navigation.
336      * @throws MedorException
337      */

338     private static QueryTreeField endOfNavigation(byte op,
339                                                   QueryTreeField qtf,
340                                                   QueryTree qt,
341                                                   String JavaDoc aliasName)
342             throws MedorException {
343         PNameField pnf = getPNameField(qtf);
344         //pnf can be null
345
logger.log(BasicLevel.DEBUG, "Computing the end of navigation with pnf=" + pnf + " for operation " + op);
346
347         if (op != NAVIGATION && pnf != null) {
348             //it is a reference
349
logger.log(BasicLevel.DEBUG, "pnf.ref=" + pnf.getReference());
350             if (pnf.getReference() instanceof GenClassRef) {
351                 // Multivalued reference => create a GenClass node and the join
352

353                 GenClassRef gcr = (GenClassRef) pnf.getReference();
354                 String JavaDoc nodeName = ((Class JavaDoc) gcr.getParent()).getFQName()
355                         + "." + gcr.getName();
356                 pnameFieldNameIndex += 1;
357                 //use the alias if possible
358
GenClassExtent extent = new GenClassExtent(
359                         gcr,
360                         nodeName,
361                         PNAME_FIELD_NAME + pnameFieldNameIndex,
362                         GENCLASS_ELEMENT_NAME);
363
364                 //'pnf' references the PNameField of the GenClass
365
pnf = (PNameField) extent.getField(extent.getPNameFieldName());
366
367                 JoinProject join;
368                 boolean newjoin = false;
369                 if (qt instanceof JoinProject) {
370                     logger.log(BasicLevel.DEBUG, "Already a join. Propagating right fields only");
371                     join = (JoinProject) qt;
372                     propagateFieldsRight(extent, join, op, aliasName);
373                 } else {
374                     logger.log(BasicLevel.DEBUG, "Creating a join. Propagating left and right fields");
375                     join = new JoinProject("" , op != NAVIGATION);
376                     propagateFieldsLeft(qt, join);
377                     propagateFieldsRight(extent, join, op, aliasName);
378                     newjoin = true;
379                 }
380
381                 //add the join condition: pnf should be equal to the
382
//PName of the extent
383
try {
384                     switch (op) {
385                     case NAVIGATION_INTO_LAST:
386                         if (newjoin) {
387                             join.setQueryFilter(new Equal(
388                                 new BasicFieldOperand(qtf),
389                                 new BasicFieldOperand(pnf)));
390                         } else {
391                             join.setQueryFilter(
392                                 new And(
393                                     join.getQueryFilter(),
394                                     new Equal(
395                                         new BasicFieldOperand(
396                                             ((PropagatedField)qtf).getPreviousFields()[0]),
397                                         new BasicFieldOperand(pnf))
398                                         )
399                                 );
400                         }
401                         return (QueryTreeField) join.getField((aliasName == null
402                                 ? extent.getElementFieldName()
403                                 : aliasName));
404                     case IS_NOT_EMPTY:
405                         if (newjoin) {
406                             join.setQueryFilter(new MemberOf(
407                                 Collections.singletonList(new BasicFieldOperand(qtf)),
408                                 Collections.singletonList(new BasicFieldOperand(pnf))));
409                         } else {
410                             join.setQueryFilter(
411                                 new And(
412                                     join.getQueryFilter(),
413                                     new MemberOf(
414                                         Collections.singletonList(new BasicFieldOperand(((PropagatedField)qtf).getPreviousFields()[0])),
415                                         Collections.singletonList(new BasicFieldOperand(pnf))
416                                         )
417                                     )
418                                 );
419                         }
420                         return (QueryTreeField) join.getField(qtf.getName());
421                     case IS_EMPTY:
422                         if (newjoin) {
423                             join.setQueryFilter(new Not(new MemberOf(
424                                     Collections.singletonList(new BasicFieldOperand(qtf)),
425                                     Collections.singletonList(new BasicFieldOperand(pnf)))));
426                         } else {
427                             join.setQueryFilter(
428                                 new And(
429                                     join.getQueryFilter(),
430                                     new Not(new MemberOf(
431                                             Collections.singletonList(new BasicFieldOperand(((PropagatedField)qtf).getPreviousFields()[0])),
432                                             Collections.singletonList(new BasicFieldOperand(pnf))
433                                         )
434                                     )
435                                 )
436                             );
437                         }
438                         return (QueryTreeField) join.getField(qtf.getName());
439                     default:
440                         throw new MedorException("Operation type not supported: " + op);
441                     }
442                 } catch (MalformedExpressionException e1) {
443                     throw new MedorException(e1);
444                 }
445             } else if (op == NAVIGATION_INTO_LAST
446                     && pnf.getReference() instanceof ClassRef) {
447
448                 ClassRef cr = (ClassRef) pnf.getReference();
449                 String JavaDoc nodeName = (aliasName == null
450                         ? cr.getMOClass().getFQName()
451                         : aliasName) + "." + cr.getName();
452                 pnameFieldNameIndex += 1;
453                 ClassExtent extent = new ClassExtent(
454                         cr.getMOClass(),
455                         nodeName,
456                         PNAME_FIELD_NAME + pnameFieldNameIndex,
457                         false);
458
459                 //'pnf' references the PNameField of the GenClass
460
pnf = (PNameField) extent.getField(extent.getPNameFieldName());
461
462                 JoinProject join = new JoinProject("", op != NAVIGATION);
463                 propagateFieldsLeft(qt, join);
464                 propagateFieldsRight(extent, join, op, null);
465                 join.setQueryFilter(new Equal(
466                         new BasicFieldOperand(qtf),
467                         new BasicFieldOperand(pnf)));
468                 qtf = pnf;
469             } else {
470                 throw new MedorException("Operation type (" + op
471                         + ") not supported on the field: " + pnf);
472             }
473         }
474         logger.log(BasicLevel.DEBUG, "End of navigation");
475         return qtf;
476     }
477
478     /**
479      * Propagates all fields from qt and, in the case of NAVIGATION_INTO_LAST,
480      * all fields from the extent into the result qn.
481      */

482     private static void propagateFieldsLeft(QueryTree qt,
483             QueryNode qn) throws MedorException {
484         //project in 'join' all fields of the inherited node
485
Field[] fToAdd = qt.getTupleStructure().getFields();
486         for (int i = 0; i < fToAdd.length; i++) {
487             logger.log(BasicLevel.DEBUG, "Propagate from left: " + fToAdd[i].getName());
488             qn.addPropagatedField(
489                     fToAdd[i].getName(),
490                     fToAdd[i].getType(),
491                     new QueryTreeField[]{(QueryTreeField) fToAdd[i]});
492         }
493     }
494     
495     private static void propagateFieldsRight(JormExtent extent,
496             QueryNode qn,
497             byte op,
498             String JavaDoc gcElemAlias) throws MedorException {
499         if (op == NAVIGATION_INTO_LAST) {
500             //project in 'join' all fields of the GenClassExtent
501
// and find the QueryTreeField which represents the element
502
Field[] fToAdd = extent.getTupleStructure().getFields();
503             String JavaDoc pnfn = extent.getPNameFieldName();
504             String JavaDoc gcElemName = null;
505             if (gcElemAlias != null) {
506                 gcElemName = ((GenClassExtent) extent).getElementFieldName();
507             }
508             //System.out.println("Right: " + extent.getName());
509
for (int i = 0; i < fToAdd.length; i++) {
510                 if (!fToAdd[i].getName().equals(pnfn)) {
511                     String JavaDoc fn = (fToAdd[i].getName().equals(gcElemName)
512                             ? gcElemAlias : fToAdd[i].getName());
513                     logger.log(BasicLevel.DEBUG, "Propagate from right: "
514                             + fToAdd[i].getName() + " to " + fn);
515                     qn.addPropagatedField(
516                             fn,
517                             fToAdd[i].getType(),
518                             new QueryTreeField[]{(QueryTreeField) fToAdd[i]});
519                 }
520             }
521         }
522     }
523
524
525     private static PNameField getPNameField(Field field) throws MedorException {
526         if (field instanceof PNameField)
527             return (PNameField) field;
528         else if (field instanceof PropagatedField) {
529             return getPNameField(
530                     ((PropagatedField) field).getPreviousFields()[0]);
531         } else
532             return null;
533     }
534
535     private static String JavaDoc contains(TupleStructure ts, String JavaDoc fn) {
536         String JavaDoc res = (ts.contains(fn) ? fn : null);
537         int idx = fn.lastIndexOf(".", fn.length());
538         while (res == null && idx != -1) {
539             res = fn.substring(idx + 1, fn.length());
540             res = (ts.contains(res) ? res : null);
541             idx = fn.lastIndexOf(".", idx - 1);
542         }
543         return res;
544     }
545
546     public static void resetNameIndexes() {
547         pnameFieldNameIndex = 0;
548     }
549
550     public static QueryTreeField navigate_old(NavigatorOperator nav,
551                                               String JavaDoc aliasName,
552                                               byte op)
553             throws MedorException {
554         //'qtf' is the QueryTreeField to use for a join
555
QueryTreeField qtf;
556         //pnf is the PNameField which must be used to access to the meta info
557
PNameField pnf;
558
559         boolean joinAlreadyConstructed = false;
560
561         String JavaDoc fieldName = null;
562         try {
563             fieldName = ((Operand) nav.getExpression(1)).getString();
564         } catch (TypingException e) {
565             throw new MedorException(e);
566         }
567         Expression e = nav.getExpression(0);
568         logger.log(BasicLevel.DEBUG, "navigate(" + aliasName + ", "
569                 + ExpressionPrinter.e2str(e) + ", " + fieldName
570                 + ", op:" + op + ")");
571         boolean propagQtf;
572         if (e instanceof FieldOperand) {
573             qtf = (QueryTreeField) ((FieldOperand) e).getField();
574             pnf = getPNameField(qtf);
575             logger.log(BasicLevel.DEBUG, "Navigation from FieldOperand " + qtf.getName());
576             propagQtf = true;
577         } else if (e instanceof NavigatorOperator) {
578             logger.log(BasicLevel.DEBUG, "Navigation from NavigatorOperator");
579             Expression el = ((NavigatorOperator) e).getExpression(0);
580             propagQtf = el instanceof FieldOperand
581                     && getPNameField(((FieldOperand) el).getField()).isClassPName();
582             //The alias name is null because only the first element (the last
583
//join) can be have an alias
584
qtf = navigate((NavigatorOperator) e, null, NAVIGATION);
585             pnf = getPNameField(qtf);
586             if (qtf.getQueryTree() instanceof JoinProject) {
587                 joinAlreadyConstructed = true;
588             }
589             logger.log(BasicLevel.DEBUG, "Recursive call constructed join ? " + joinAlreadyConstructed);
590
591         } else
592             throw new MedorException(
593                     "Unknown left operand of the specified NavigatorOperand: " + e);
594
595         logger.log(BasicLevel.DEBUG, "propagQtf=" + propagQtf);
596         logger.log(BasicLevel.DEBUG, "qtf=" + qtf.getName() + " of node " + qtf.getQueryTree());
597         if (pnf == null)
598             throw new MedorException("Impossible to find a PNameField");
599
600         // 'qt' is the QueryTree of 'qtf"
601
QueryTree qt = qtf.getQueryTree();
602
603         if (!pnf.isClassPName()) {
604             logger.log(BasicLevel.DEBUG, "Reference from a Class to a Class");
605             Reference ref = pnf.getReference();
606
607             Class JavaDoc jormClass = null;
608             if (ref instanceof ClassRef)
609                 jormClass = ((ClassRef) ref).getMOClass();
610             else
611                 throw new MedorException("Impossible to navigate with PName:"
612                         + ref.getName() + " " + ref.getParent());
613
614             ClassExtent extent = null;
615             String JavaDoc nodeName;
616             if (aliasName != null) {
617                 //this is the end of the navigation
618
nodeName = (op != NAVIGATION_INTO_LAST
619                         ? aliasName
620                         : jormClass.getFQName());
621                 pnameFieldNameIndex += 1;
622                 //create the extent corresponding to the reference
623
extent = new ClassExtent(
624                         jormClass,
625                         nodeName,
626                         PNAME_FIELD_NAME + pnameFieldNameIndex,
627                         false);
628             } else {
629                 //in the middle of the navigation: propagate only the required
630
//field
631
nodeName = jormClass.getFQName();
632                 pnameFieldNameIndex += 1;
633                 //create the extent corresponding to the reference
634
extent = new ClassExtent(
635                         jormClass,
636                         nodeName,
637                         new String JavaDoc[]{fieldName},
638                         true,
639                         PNAME_FIELD_NAME + pnameFieldNameIndex);
640             }
641             // pnf references the PNameField of the joined extent
642
pnf = (PNameField) extent.getField(extent.getPNameFieldName());
643
644             JoinProject join;
645             //if (!joinAlreadyConstructed) {
646
join = new JoinProject("", op != NAVIGATION);
647             //} else {
648
// join = (JoinProject) qtf.getQueryTree();
649
// propagQtf = false;
650
//}
651

652             //add the join condition: pnf should be equal to the
653
//PName of the extent
654
join.setQueryFilter(
655                     new Equal(
656                             new BasicFieldOperand(qtf),
657                             new BasicFieldOperand(pnf)
658                     )
659             );
660
661             //project in qt all fields of the QueryTree containing
662
//the origin of the path expression
663
Field[] fToAdd = qt.getTupleStructure().getFields();
664             logger.log(BasicLevel.DEBUG, "Adding fields:");
665
666             for (int i = 0; i < fToAdd.length; i++) {
667                 if (propagQtf || qtf != fToAdd[i]) {
668                     logger.log(BasicLevel.DEBUG, "\t-" + fToAdd[i].getName());
669                     join.addPropagatedField(
670                             fToAdd[i].getName(),
671                             fToAdd[i].getType(),
672                             new QueryTreeField[]{(QueryTreeField) fToAdd[i]});
673                 }
674                 //else
675
//System.out.println("\t-Do not propagate " + fToAdd[i].getName());
676
}
677
678             // project in qt the fields corresponding to the end of the path
679
// expression
680
fToAdd = extent.getTupleStructure().getFields();
681             for (int i = 0; i < fToAdd.length; i++) {
682                 logger.log(BasicLevel.DEBUG, "Adding propagated field " + fToAdd[i].getName());
683                 join.addPropagatedField(
684                         fToAdd[i].getName(),
685                         fToAdd[i].getType(),
686                         new QueryTreeField[]{(QueryTreeField) fToAdd[i]});
687             }
688             qtf = (QueryTreeField)
689                     join.getField(extent.getFieldName(nodeName, fieldName));
690             //qtf references a propagated field to a field named 'fieldName'
691

692             qt = join;
693         } else {
694             logger.log(BasicLevel.DEBUG, "Adding the field if not already present");
695             if (pnf.isInGenClass()) {
696                 throw new MedorException(
697                         "Impossible to navigate with a multi valued reference");
698             }
699             logger.log(BasicLevel.DEBUG, "Checking that " + fieldName + " appears in " + qt);
700             // The field 'fieldName' must be found on 'qt'
701
String JavaDoc fn = contains(qt.getTupleStructure(),
702                     pnf.getQueryTree().getName() + "." + fieldName);
703             if (fn != null) {
704                 qtf = (QueryTreeField) qt.getTupleStructure().getField(fn);
705             } else if (qt instanceof ClassExtent) {
706                 //In case where qt is a ClassExtent
707
ClassExtent extent = (ClassExtent) qt;
708                 TypedElement te =
709                         ((Class JavaDoc) extent.getMetaObject()).getTypedElement(fieldName);
710                 if (te == null)
711                     throw new MedorException("The jorm class "
712                             + ((Class JavaDoc) extent.getMetaObject()).getName()
713                             + " does not provide a field " + fieldName);
714                 qtf = extent.addField(te);
715             } else
716                 throw new MedorException(
717                         "No field " + fieldName + " found on the query tree " + qt);
718         }
719         return endOfNavigation(op, qtf, qt, aliasName);
720     }
721
722
723 }
724
Popular Tags