svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.file / org.gvsig.fmap.dal.file.dbf / src / test / java / org / gvsig / fmap / dal / store / dbf / JoinTransform.java @ 40435
History | View | Annotate | Download (9.28 KB)
1 | 40435 | jjdelcerro | package org.gvsig.fmap.dal.store.dbf; |
---|---|---|---|
2 | |||
3 | import java.util.ArrayList; |
||
4 | import java.util.Arrays; |
||
5 | import java.util.HashMap; |
||
6 | import java.util.Iterator; |
||
7 | import java.util.Map; |
||
8 | import java.util.Map.Entry; |
||
9 | |||
10 | import org.gvsig.fmap.dal.exception.DataException; |
||
11 | import org.gvsig.fmap.dal.feature.AbstractFeatureStoreTransform; |
||
12 | import org.gvsig.tools.dispose.DisposableIterator; |
||
13 | import org.gvsig.fmap.dal.feature.EditableFeature; |
||
14 | import org.gvsig.fmap.dal.feature.EditableFeatureType; |
||
15 | import org.gvsig.fmap.dal.feature.Feature; |
||
16 | import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor; |
||
17 | import org.gvsig.fmap.dal.feature.FeatureQuery; |
||
18 | import org.gvsig.fmap.dal.feature.FeatureSet; |
||
19 | import org.gvsig.fmap.dal.feature.FeatureStore; |
||
20 | import org.gvsig.fmap.dal.feature.FeatureType; |
||
21 | import org.gvsig.tools.evaluator.Evaluator; |
||
22 | import org.gvsig.tools.evaluator.EvaluatorData; |
||
23 | import org.gvsig.tools.evaluator.EvaluatorException; |
||
24 | import org.gvsig.tools.evaluator.EvaluatorFieldsInfo; |
||
25 | import org.gvsig.tools.persistence.PersistentState; |
||
26 | import org.gvsig.tools.persistence.exception.PersistenceException; |
||
27 | |||
28 | public class JoinTransform extends AbstractFeatureStoreTransform { |
||
29 | |||
30 | /**
|
||
31 | * Store from which the join transform will get the additional attributes
|
||
32 | */
|
||
33 | private FeatureStore store2;
|
||
34 | |||
35 | /**
|
||
36 | * name of the key attr in store1 that will be used to match features in
|
||
37 | * store2
|
||
38 | */
|
||
39 | private String keyAttr1; |
||
40 | |||
41 | /**
|
||
42 | * name of the key attr in store2 that will be used to match features in
|
||
43 | * store1
|
||
44 | */
|
||
45 | private String keyAttr2; |
||
46 | |||
47 | /**
|
||
48 | * names of the attributes to join from store2 to store1
|
||
49 | */
|
||
50 | private String[] attrs; |
||
51 | |||
52 | /**
|
||
53 | * Attribute names may change after transformation if they are repeated in
|
||
54 | * both stores. This map keeps correspondence between store2 original names
|
||
55 | * and their transformed counterparts.
|
||
56 | */
|
||
57 | private Map targetNamesMap; |
||
58 | |||
59 | private JoinTransformEvaluator evaluator = null; |
||
60 | |||
61 | private FeatureType originalFeatureType;
|
||
62 | |||
63 | private String[] attrsForQuery; |
||
64 | |||
65 | private String prefix1; |
||
66 | |||
67 | private String prefix2; |
||
68 | |||
69 | /**
|
||
70 | * A default constructor
|
||
71 | */
|
||
72 | public JoinTransform() {
|
||
73 | targetNamesMap = new HashMap(); |
||
74 | } |
||
75 | |||
76 | /**
|
||
77 | * Initializes all the necessary data for this transform
|
||
78 | *
|
||
79 | * @param store1
|
||
80 | * store whose default feature type is the target of this
|
||
81 | * transform
|
||
82 | *
|
||
83 | * @param store2
|
||
84 | * store whose default feature type will provide the new
|
||
85 | * attributes to join
|
||
86 | *
|
||
87 | * @param keyAttr1
|
||
88 | * key attribute in store1 that matches keyAttr2 in store2
|
||
89 | * (foreign key), used for joining both stores.
|
||
90 | *
|
||
91 | * @param keyAttr2
|
||
92 | * key attribute in store2 that matches keyAttr1 in store2
|
||
93 | * (foreign key), used for joining both stores.
|
||
94 | *
|
||
95 | * @param attrs
|
||
96 | * names of the attributes in store2 that will be joined to
|
||
97 | * store1.
|
||
98 | */
|
||
99 | public void initialize(FeatureStore store1, FeatureStore store2, |
||
100 | String keyAttr1, String keyAttr2, String prefix1, String prefix2, |
||
101 | String[] attrs) |
||
102 | throws DataException {
|
||
103 | |||
104 | if (store1 == store2) {
|
||
105 | throw new IllegalArgumentException("store1 == store2"); |
||
106 | } |
||
107 | |||
108 | // Initialize needed data
|
||
109 | this.setFeatureStore(store1);
|
||
110 | this.store2 = store2;
|
||
111 | this.keyAttr1 = keyAttr1;
|
||
112 | this.keyAttr2 = keyAttr2;
|
||
113 | this.prefix1 = prefix1; // TODO |
||
114 | this.prefix2 = prefix2; // TODO |
||
115 | this.attrs = attrs;
|
||
116 | |||
117 | // calculate this transform resulting feature type
|
||
118 | // by adding all specified attrs from store2 to store1's default
|
||
119 | // feature type
|
||
120 | // FIXME for more than one FTypes ??
|
||
121 | this.originalFeatureType = this.getFeatureStore() |
||
122 | .getDefaultFeatureType(); |
||
123 | |||
124 | // TODO tener en cuenta prefix1
|
||
125 | EditableFeatureType type = this.getFeatureStore().getDefaultFeatureType().getEditable();
|
||
126 | |||
127 | FeatureType type2 = store2.getDefaultFeatureType(); |
||
128 | |||
129 | // TODO tener en cuenta prefix2
|
||
130 | for (int i = 0; i < attrs.length; i++) { |
||
131 | String name = attrs[i];
|
||
132 | |||
133 | // If an attribute already exists with the same name in store1's
|
||
134 | // default feature type,
|
||
135 | // calculate an alternate name and add it to our type
|
||
136 | int j = 0; |
||
137 | while (type.getIndex(name) >= 0) { |
||
138 | name = attrs[i] + "_" + ++j;
|
||
139 | } |
||
140 | type.add(name, |
||
141 | type2.getAttributeDescriptor(attrs[i]).getType()); |
||
142 | |||
143 | // keep correspondence between original name and transformed name
|
||
144 | this.targetNamesMap.put(attrs[i], name);
|
||
145 | } |
||
146 | if (this.targetNamesMap.containsKey(keyAttr2)) { |
||
147 | this.attrsForQuery = this.attrs; |
||
148 | } else {
|
||
149 | ArrayList list = new ArrayList(this.attrs.length + 1); |
||
150 | list.addAll(Arrays.asList(this.attrs)); |
||
151 | list.add(keyAttr2); |
||
152 | this.attrsForQuery = (String[]) list.toArray(new String[] {}); |
||
153 | } |
||
154 | |||
155 | // assign calculated feature type as this transform's feature type
|
||
156 | FeatureType[] types = new FeatureType[] { type.getNotEditableCopy() }; |
||
157 | setFeatureTypes(Arrays.asList(types), types[0]); |
||
158 | } |
||
159 | |||
160 | /**
|
||
161 | *
|
||
162 | *
|
||
163 | * @param source
|
||
164 | *
|
||
165 | * @param target
|
||
166 | *
|
||
167 | * @throws DataException
|
||
168 | */
|
||
169 | public void applyTransform(Feature source, EditableFeature target) |
||
170 | throws DataException {
|
||
171 | |||
172 | // copy the data from store1 into the resulting feature
|
||
173 | this.copySourceToTarget(source, target);
|
||
174 | |||
175 | // ask store2 for the specified attributes, filtering by the key
|
||
176 | // attribute value
|
||
177 | // from the source feature
|
||
178 | JoinTransformEvaluator eval = this.getEvaluator();
|
||
179 | eval.updateValue(source.get(this.keyAttr1));
|
||
180 | |||
181 | FeatureQuery query = this.getFeatureStore().createFeatureQuery();
|
||
182 | query.setAttributeNames(attrsForQuery); |
||
183 | query.setFilter(eval); |
||
184 | |||
185 | FeatureSet set = store2.getFeatureSet(query); |
||
186 | |||
187 | // In this join implementation, we will take only the first matching
|
||
188 | // feature found in store2
|
||
189 | |||
190 | FeatureAttributeDescriptor attr; |
||
191 | Feature feat; |
||
192 | String targetName;
|
||
193 | |||
194 | Iterator itAttr;
|
||
195 | |||
196 | DisposableIterator itFeat = set.iterator(); |
||
197 | if (itFeat.hasNext()) {
|
||
198 | feat = (Feature) itFeat.next(); |
||
199 | |||
200 | // copy all attributes from joined feature to target
|
||
201 | this.copyJoinToTarget(feat, target);
|
||
202 | } |
||
203 | itFeat.dispose(); |
||
204 | set.dispose(); |
||
205 | } |
||
206 | |||
207 | /**
|
||
208 | * @param feat
|
||
209 | * @param target
|
||
210 | */
|
||
211 | private void copyJoinToTarget(Feature join, EditableFeature target) { |
||
212 | Iterator iter = targetNamesMap.entrySet()
|
||
213 | .iterator(); |
||
214 | Entry entry; |
||
215 | FeatureType trgType = target.getType(); |
||
216 | FeatureAttributeDescriptor attr; |
||
217 | while (iter.hasNext()) {
|
||
218 | entry = (Entry) iter.next(); |
||
219 | attr = trgType.getAttributeDescriptor((String) entry.getValue());
|
||
220 | if (attr != null) { |
||
221 | target.set(attr.getIndex(), join.get((String) entry.getKey()));
|
||
222 | } |
||
223 | } |
||
224 | |||
225 | |||
226 | } |
||
227 | |||
228 | /**
|
||
229 | * @param source
|
||
230 | * @param target
|
||
231 | */
|
||
232 | private void copySourceToTarget(Feature source, EditableFeature target) { |
||
233 | FeatureAttributeDescriptor attr, attrTrg; |
||
234 | FeatureType ftSrc = source.getType(); |
||
235 | FeatureType ftTrg = target.getType(); |
||
236 | |||
237 | |||
238 | for (int i = 0; i < source.getType().size(); i++) { |
||
239 | attr = ftSrc.getAttributeDescriptor(i); |
||
240 | if (ftTrg.getIndex(attr.getName()) > -1) { |
||
241 | try {
|
||
242 | target.set(attr.getName(), source.get(i)); |
||
243 | } catch (IllegalArgumentException e) { |
||
244 | attrTrg = ftTrg.getAttributeDescriptor(attr.getName()); |
||
245 | target.set(attrTrg.getIndex(), attrTrg.getDefaultValue()); |
||
246 | } |
||
247 | |||
248 | } |
||
249 | } |
||
250 | |||
251 | } |
||
252 | |||
253 | private JoinTransformEvaluator getEvaluator() {
|
||
254 | if (this.evaluator == null){ |
||
255 | this.evaluator = new JoinTransformEvaluator(keyAttr2); |
||
256 | } |
||
257 | return evaluator;
|
||
258 | |||
259 | } |
||
260 | |||
261 | private class JoinTransformEvaluator implements Evaluator { |
||
262 | |||
263 | private String attribute; |
||
264 | private Object value; |
||
265 | private String sql; |
||
266 | private EvaluatorFieldsInfo info = null; |
||
267 | |||
268 | // private int attributeIndex;
|
||
269 | |||
270 | public JoinTransformEvaluator(String attribute) { |
||
271 | this.attribute = attribute;
|
||
272 | this.value = null; |
||
273 | this.info = new EvaluatorFieldsInfo(); |
||
274 | |||
275 | // this.attributeIndex = attrIndex;
|
||
276 | } |
||
277 | |||
278 | public void updateValue(Object value) { |
||
279 | this.value = value;
|
||
280 | this.sql = this.attribute + "= '" + this.value + "'"; |
||
281 | this.info = new EvaluatorFieldsInfo(); |
||
282 | this.info.addMatchFieldValue(this.attribute, value); |
||
283 | } |
||
284 | |||
285 | public Object evaluate(EvaluatorData arg0) throws EvaluatorException { |
||
286 | Object curValue = arg0.getDataValue(attribute);
|
||
287 | if (curValue == null) { |
||
288 | return new Boolean(value == null); |
||
289 | } |
||
290 | return new Boolean(curValue.equals(value)); |
||
291 | } |
||
292 | |||
293 | public String getSQL() { |
||
294 | return this.sql; |
||
295 | } |
||
296 | |||
297 | public String getDescription() { |
||
298 | return "Evaluates join transform match"; |
||
299 | } |
||
300 | |||
301 | public String getName() { |
||
302 | return "JoinTransformEvaluator"; |
||
303 | } |
||
304 | |||
305 | public EvaluatorFieldsInfo getFieldsInfo() {
|
||
306 | return this.info; |
||
307 | } |
||
308 | |||
309 | } |
||
310 | |||
311 | public void saveToState(PersistentState state) throws PersistenceException { |
||
312 | // TODO Auto-generated method stub
|
||
313 | |||
314 | } |
||
315 | |||
316 | public void loadFromState(PersistentState state) throws PersistenceException { |
||
317 | // TODO Auto-generated method stub
|
||
318 | |||
319 | } |
||
320 | |||
321 | public FeatureType getSourceFeatureTypeFrom(FeatureType arg0) {
|
||
322 | EditableFeatureType orgType = originalFeatureType.getEditable(); |
||
323 | Iterator iter = arg0.iterator();
|
||
324 | FeatureAttributeDescriptor attr; |
||
325 | ArrayList toRetain = new ArrayList(); |
||
326 | while (iter.hasNext()) {
|
||
327 | attr = (FeatureAttributeDescriptor) iter.next(); |
||
328 | if (this.targetNamesMap.containsValue(attr.getName())) { |
||
329 | continue;
|
||
330 | } |
||
331 | toRetain.add(attr.getName()); |
||
332 | } |
||
333 | |||
334 | if (!toRetain.contains(keyAttr1)) {
|
||
335 | toRetain.add(keyAttr1); |
||
336 | } |
||
337 | |||
338 | iter = originalFeatureType.iterator(); |
||
339 | while (iter.hasNext()) {
|
||
340 | attr = (FeatureAttributeDescriptor) iter.next(); |
||
341 | if (!toRetain.contains(attr.getName())) {
|
||
342 | orgType.remove(attr.getName()); |
||
343 | } |
||
344 | |||
345 | } |
||
346 | |||
347 | return orgType.getNotEditableCopy();
|
||
348 | } |
||
349 | |||
350 | public boolean isTransformsOriginalValues() { |
||
351 | return false; |
||
352 | } |
||
353 | } |