KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > access > jdbc > EJBQLPathTranslator


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19 package org.apache.cayenne.access.jdbc;
20
21 import java.util.HashMap JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Map JavaDoc;
25
26 import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
27 import org.apache.cayenne.ejbql.EJBQLException;
28 import org.apache.cayenne.ejbql.EJBQLExpression;
29 import org.apache.cayenne.ejbql.parser.EJBQLIdentificationVariable;
30 import org.apache.cayenne.ejbql.parser.EJBQLIdentifier;
31 import org.apache.cayenne.ejbql.parser.EJBQLInnerJoin;
32 import org.apache.cayenne.ejbql.parser.EJBQLPath;
33 import org.apache.cayenne.map.DbEntity;
34 import org.apache.cayenne.map.DbJoin;
35 import org.apache.cayenne.map.DbRelationship;
36 import org.apache.cayenne.map.ObjAttribute;
37 import org.apache.cayenne.map.ObjEntity;
38 import org.apache.cayenne.map.ObjRelationship;
39 import org.apache.cayenne.reflect.ClassDescriptor;
40
41 /**
42  * A translator that walks the relationship/attribute path, appending joins to the query.
43  *
44  * @since 3.0
45  * @author Andrus Adamchik
46  */

47 abstract class EJBQLPathTranslator extends EJBQLBaseVisitor {
48
49     private EJBQLTranslationContext context;
50     protected ObjEntity currentEntity;
51     private String JavaDoc lastPathComponent;
52     protected String JavaDoc lastAlias;
53     protected String JavaDoc idPath;
54     protected String JavaDoc joinMarker;
55     private String JavaDoc fullPath;
56     private EJBQLFromTranslator joinAppender;
57
58     EJBQLPathTranslator(EJBQLTranslationContext context) {
59         super(true);
60         this.context = context;
61     }
62
63     protected abstract void appendMultiColumnPath(EJBQLMultiColumnOperand operand);
64
65     public boolean visitPath(EJBQLPath expression, int finishedChildIndex) {
66
67         if (finishedChildIndex > 0) {
68
69             if (finishedChildIndex + 1 < expression.getChildrenCount()) {
70                 processIntermediatePathComponent();
71             }
72             else {
73                 processLastPathComponent();
74             }
75         }
76
77         return true;
78     }
79
80     public boolean visitIdentifier(EJBQLExpression expression) {
81         ClassDescriptor descriptor = context.getCompiledExpression().getEntityDescriptor(
82                 expression.getText());
83         if (descriptor == null) {
84             throw new EJBQLException("Invalid identification variable: "
85                     + expression.getText());
86         }
87
88         this.currentEntity = descriptor.getEntity();
89         this.idPath = expression.getText();
90         this.joinMarker = EJBQLFromTranslator.makeJoinTailMarker(idPath);
91         this.fullPath = idPath;
92         return true;
93     }
94
95     public boolean visitIdentificationVariable(EJBQLExpression expression) {
96
97         // TODO: andrus 6/11/2007 - if the path ends with relationship, the last join will
98
// get lost...
99
if (lastPathComponent != null) {
100             resolveJoin();
101         }
102
103         this.lastPathComponent = expression.getText();
104         return true;
105     }
106
107     private EJBQLFromTranslator getJoinAppender() {
108         if (joinAppender == null) {
109             joinAppender = new EJBQLFromTranslator(context);
110         }
111
112         return joinAppender;
113     }
114
115     private void resolveJoin() {
116
117         String JavaDoc newPath = idPath + '.' + lastPathComponent;
118         String JavaDoc oldPath = context.registerReusableJoin(idPath, lastPathComponent, newPath);
119
120         this.fullPath = fullPath + '.' + lastPathComponent;
121
122         if (oldPath != null) {
123             this.idPath = oldPath;
124             this.lastAlias = context.getTableAlias(oldPath, currentEntity
125                     .getDbEntityName());
126         }
127         else {
128             // register join
129
EJBQLIdentifier id = new EJBQLIdentifier(-1);
130             id.setText(idPath);
131
132             EJBQLIdentificationVariable idVar = new EJBQLIdentificationVariable(-1);
133             idVar.setText(lastPathComponent);
134
135             EJBQLPath path = new EJBQLPath(-1);
136             path.jjtAddChild(id, 0);
137             path.jjtAddChild(idVar, 1);
138
139             EJBQLIdentifier joinId = new EJBQLIdentifier(-1);
140             joinId.setText(fullPath);
141
142             EJBQLInnerJoin join = new EJBQLInnerJoin(-1);
143             join.jjtAddChild(path, 0);
144             join.jjtAddChild(joinId, 1);
145
146             context.switchToMarker(joinMarker);
147
148             getJoinAppender().visitInnerJoin(join);
149             context.switchToMainBuffer();
150
151             this.idPath = newPath;
152             this.lastAlias = context.getTableAlias(fullPath, currentEntity
153                     .getDbEntityName());
154         }
155     }
156
157     private void processIntermediatePathComponent() {
158         ObjRelationship relationship = (ObjRelationship) currentEntity
159                 .getRelationship(lastPathComponent);
160         if (relationship == null) {
161             throw new EJBQLException("Unknown relationship '"
162                     + lastPathComponent
163                     + "' for entity '"
164                     + currentEntity.getName()
165                     + "'");
166         }
167
168         this.currentEntity = (ObjEntity) relationship.getTargetEntity();
169     }
170
171     private void processLastPathComponent() {
172
173         ObjAttribute attribute = (ObjAttribute) currentEntity
174                 .getAttribute(lastPathComponent);
175
176         if (attribute != null) {
177             processTerminatingAttribute(attribute);
178             return;
179         }
180
181         ObjRelationship relationship = (ObjRelationship) currentEntity
182                 .getRelationship(lastPathComponent);
183         if (relationship != null) {
184             processTerminatingRelationship(relationship);
185             return;
186         }
187
188         throw new IllegalStateException JavaDoc("Invalid path component: " + lastPathComponent);
189     }
190
191     protected void processTerminatingAttribute(ObjAttribute attribute) {
192
193         DbEntity table = currentEntity.getDbEntity();
194         String JavaDoc alias = this.lastAlias != null ? lastAlias : context.getTableAlias(
195                 idPath,
196                 table.getFullyQualifiedName());
197         context.append(' ').append(alias).append('.').append(
198                 attribute.getDbAttributeName());
199     }
200
201     private void processTerminatingRelationship(ObjRelationship relationship) {
202
203         // check whether we need a join
204
if (relationship.isSourceIndependentFromTargetChange()) {
205             // TODO: andrus, 6/13/2007 - implement
206
}
207         else {
208             // match FK against the target object
209

210             // TODO: andrus, 6/21/2007 - flattened support
211
DbRelationship dbRelationship = (DbRelationship) relationship
212                     .getDbRelationships()
213                     .get(0);
214             DbEntity table = (DbEntity) dbRelationship.getSourceEntity();
215
216             String JavaDoc alias = this.lastAlias != null ? lastAlias : context.getTableAlias(
217                     idPath,
218                     table.getFullyQualifiedName());
219
220             List JavaDoc joins = dbRelationship.getJoins();
221
222             if (joins.size() == 1) {
223                 DbJoin join = (DbJoin) joins.get(0);
224                 context
225                         .append(' ')
226                         .append(alias)
227                         .append('.')
228                         .append(join.getSourceName());
229             }
230             else {
231                 Map JavaDoc multiColumnMatch = new HashMap JavaDoc(joins.size() + 2);
232
233                 Iterator JavaDoc it = joins.iterator();
234                 while (it.hasNext()) {
235                     DbJoin join = (DbJoin) it.next();
236                     String JavaDoc column = alias + "." + join.getSourceName();
237
238                     multiColumnMatch.put(join.getTargetName(), column);
239                 }
240
241                 appendMultiColumnPath(EJBQLMultiColumnOperand.getPathOperand(
242                         context,
243                         multiColumnMatch));
244             }
245         }
246     }
247 }
248
Popular Tags