Source Code Cross Referenced for FilterToSQL.java in  » GIS » GeoTools-2.4.1 » org » geotools » data » jdbc » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.data.jdbc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2002-2006, GeoTools Project Managment Committee (PMC)
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;
009:         *    version 2.1 of the License.
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:        package org.geotools.data.jdbc;
017:
018:        import java.io.IOException;
019:        import java.io.StringWriter;
020:        import java.io.Writer;
021:        import java.util.Arrays;
022:        import java.util.HashMap;
023:        import java.util.Map;
024:        import java.util.logging.Logger;
025:
026:        import org.geotools.data.jdbc.fidmapper.FIDMapper;
027:        import org.geotools.feature.AttributeType;
028:        import org.geotools.feature.FeatureType;
029:        import org.geotools.filter.FilterCapabilities;
030:        import org.geotools.filter.LikeFilterImpl;
031:        import org.geotools.util.Converters;
032:        import org.opengis.filter.And;
033:        import org.opengis.filter.BinaryComparisonOperator;
034:        import org.opengis.filter.BinaryLogicOperator;
035:        import org.opengis.filter.ExcludeFilter;
036:        import org.opengis.filter.Filter;
037:        import org.opengis.filter.FilterVisitor;
038:        import org.opengis.filter.Id;
039:        import org.opengis.filter.IncludeFilter;
040:        import org.opengis.filter.Not;
041:        import org.opengis.filter.Or;
042:        import org.opengis.filter.PropertyIsBetween;
043:        import org.opengis.filter.PropertyIsEqualTo;
044:        import org.opengis.filter.PropertyIsGreaterThan;
045:        import org.opengis.filter.PropertyIsGreaterThanOrEqualTo;
046:        import org.opengis.filter.PropertyIsLessThan;
047:        import org.opengis.filter.PropertyIsLessThanOrEqualTo;
048:        import org.opengis.filter.PropertyIsLike;
049:        import org.opengis.filter.PropertyIsNotEqualTo;
050:        import org.opengis.filter.PropertyIsNull;
051:        import org.opengis.filter.expression.Add;
052:        import org.opengis.filter.expression.BinaryExpression;
053:        import org.opengis.filter.expression.Divide;
054:        import org.opengis.filter.expression.Expression;
055:        import org.opengis.filter.expression.ExpressionVisitor;
056:        import org.opengis.filter.expression.Function;
057:        import org.opengis.filter.expression.Literal;
058:        import org.opengis.filter.expression.Multiply;
059:        import org.opengis.filter.expression.NilExpression;
060:        import org.opengis.filter.expression.PropertyName;
061:        import org.opengis.filter.expression.Subtract;
062:        import org.opengis.filter.identity.FeatureId;
063:        import org.opengis.filter.spatial.BBOX;
064:        import org.opengis.filter.spatial.Beyond;
065:        import org.opengis.filter.spatial.BinarySpatialOperator;
066:        import org.opengis.filter.spatial.Contains;
067:        import org.opengis.filter.spatial.Crosses;
068:        import org.opengis.filter.spatial.DWithin;
069:        import org.opengis.filter.spatial.Disjoint;
070:        import org.opengis.filter.spatial.Equals;
071:        import org.opengis.filter.spatial.Intersects;
072:        import org.opengis.filter.spatial.Overlaps;
073:        import org.opengis.filter.spatial.Touches;
074:        import org.opengis.filter.spatial.Within;
075:
076:        import com.vividsolutions.jts.geom.Geometry;
077:
078:        /**
079:         * Encodes a filter into a SQL WHERE statement.  It should hopefully be generic
080:         * enough that any SQL database will work with it.
081:         * This generic SQL encoder should eventually
082:         * be able to encode all filters except Geometry Filters.
083:         * This is because the OGC's SFS for SQL document specifies
084:         * two ways of doing SQL databases, one with native geometry types and one
085:         * without.  To implement an encoder for one of the two types simply subclass
086:         * off of this encoder and put in the proper GeometryFilter visit method. Then
087:         * add the filter types supported to the capabilities by overriding the
088:         * {{@link #createFilterCapabilities()} method.
089:         * 
090:         * 
091:         * This version was ported from the original to support org.opengis.filter type
092:         * Filters.
093:         *
094:         * @author originally by Chris Holmes, TOPP
095:         * @author ported by Saul Farber, MassGIS
096:         *
097:         * @task REVISIT: need to figure out exceptions, we're currently eating io
098:         *       errors, which is bad. Probably need a generic visitor exception.
099:         * 
100:         */
101:        /*
102:         * TODO: Use the new FilterCapabilities.  This may fall out of using the new
103:         * PrePostFilterSplitter code.
104:         * 
105:         * TODO: Use the new Geometry classes from org.opengis.  Not sure
106:         * when this will be required, but it's on the horizon here.
107:         * 
108:         * Non Javadoc comments:
109:         * 
110:         * Note that the old method allowed us to write WAY fewer methods, as we didn't
111:         * need to cover all the cases with exlpicit methods (as the new
112:         * org.opengis.filter.FilterVisitor and ExpressionVisitor methods require
113:         * us to do).
114:         * 
115:         * The code is split into methods to support the FilterVisitor interface first
116:         * then the ExpressionVisitor methods second.
117:         *  
118:         */
119:        public class FilterToSQL implements  FilterVisitor, ExpressionVisitor {
120:            /** error message for exceptions */
121:            protected static final String IO_ERROR = "io problem writing filter";
122:
123:            /** The filter types that this class can encode */
124:            protected FilterCapabilities capabilities = null;
125:
126:            /** Standard java logger */
127:            private static Logger LOGGER = org.geotools.util.logging.Logging
128:                    .getLogger("org.geotools.filter");
129:
130:            /** Map of expression types to sql representation */
131:            private static Map expressions = new HashMap();
132:
133:            static {
134:                expressions.put(Add.class, "+");
135:                expressions.put(Divide.class, "/");
136:                expressions.put(Multiply.class, "*");
137:                expressions.put(Subtract.class, "-");
138:            }
139:
140:            /** Character used to escape database schema, table and column names */
141:            private String sqlNameEscape = "";
142:
143:            /** where to write the constructed string from visiting the filters. */
144:            protected Writer out;
145:
146:            /** the fid mapper used to encode the fid filters */
147:            protected FIDMapper mapper;
148:
149:            /** the schmema the encoder will be used to be encode sql for */
150:            protected FeatureType featureType;
151:
152:            /**
153:             * Default constructor
154:             */
155:            public FilterToSQL() {
156:            }
157:
158:            public FilterToSQL(Writer out) {
159:                this .out = out;
160:            }
161:
162:            /**
163:             * Performs the encoding, sends the encoded sql to the writer passed in.
164:             *
165:             * @param filter the Filter to be encoded.
166:             *
167:             * @throws OpenGISFilterToOpenGISFilterToSQLEncoderException If filter type not supported, or if there
168:             *         were io problems.
169:             */
170:            public void encode(Filter filter) throws FilterToSQLException {
171:                if (out == null)
172:                    throw new FilterToSQLException(
173:                            "Can't encode to a null writer.");
174:                if (getCapabilities().fullySupports(filter)) {
175:
176:                    try {
177:                        out.write("WHERE ");
178:                        filter.accept(this , null);
179:
180:                        //out.write(";");
181:                    } catch (java.io.IOException ioe) {
182:                        LOGGER.warning("Unable to export filter" + ioe);
183:                        throw new FilterToSQLException(
184:                                "Problem writing filter: ", ioe);
185:                    }
186:                } else {
187:                    throw new FilterToSQLException("Filter type not supported");
188:                }
189:            }
190:
191:            /**
192:             * purely a convenience method.
193:             * 
194:             * Equivalent to:
195:             * 
196:             *  StringWriter out = new StringWriter();
197:             *  new FilterToSQL(out).encode(filter);
198:             *  out.getBuffer().toString();
199:             * 
200:             * @param filter
201:             * @return a string representing the filter encoded to SQL.
202:             * @throws FilterToSQLException
203:             */
204:
205:            public String encodeToString(Filter filter)
206:                    throws FilterToSQLException {
207:                StringWriter out = new StringWriter();
208:                this .out = out;
209:                this .encode(filter);
210:                return out.getBuffer().toString();
211:            }
212:
213:            /**
214:             * Sets the featuretype the encoder is encoding sql for.
215:             * <p>
216:             * This is used for context for attribute expressions when encoding to sql. 
217:             * </p>
218:             * 
219:             * @param featureType
220:             */
221:            public void setFeatureType(FeatureType featureType) {
222:                this .featureType = featureType;
223:            }
224:
225:            /**
226:             * Sets the FIDMapper that will be used in subsequente visit calls. There
227:             * must be a FIDMapper in order to invoke the FIDFilter encoder.
228:             *
229:             * @param mapper
230:             */
231:            public void setFIDMapper(FIDMapper mapper) {
232:                this .mapper = mapper;
233:            }
234:
235:            /**
236:             * Sets the capabilities of this filter.
237:             *
238:             * @return FilterCapabilities for this Filter
239:             */
240:            protected FilterCapabilities createFilterCapabilities() {
241:                FilterCapabilities capabilities = new FilterCapabilities();
242:
243:                capabilities.addAll(FilterCapabilities.LOGICAL_OPENGIS);
244:                capabilities
245:                        .addAll(FilterCapabilities.SIMPLE_COMPARISONS_OPENGIS);
246:                capabilities.addType(PropertyIsNull.class);
247:                capabilities.addType(PropertyIsBetween.class);
248:                capabilities.addType(Id.class);
249:                capabilities.addType(IncludeFilter.class);
250:                capabilities.addType(ExcludeFilter.class);
251:
252:                return capabilities;
253:            }
254:
255:            /**
256:             * Describes the capabilities of this encoder.
257:             * 
258:             * <p>
259:             * Performs lazy creation of capabilities.
260:             * </p>
261:             * 
262:             * If you're subclassing this class, override createFilterCapabilities
263:             * to declare which filtercapabilities you support.  Don't use
264:             * this method.
265:             *
266:             * @return The capabilities supported by this encoder.
267:             */
268:            public synchronized final FilterCapabilities getCapabilities() {
269:                if (capabilities == null) {
270:                    capabilities = createFilterCapabilities();
271:                }
272:
273:                return capabilities; //maybe clone?  Make immutable somehow
274:            }
275:
276:            // BEGIN IMPLEMENTING org.opengis.filter.FilterVisitor METHODS
277:
278:            /**
279:             * @see {@link FilterVisitor#visit(ExcludeFilter, Object)}
280:             * 
281:             * Writes the SQL for the IncludeFilter by writing "FALSE".
282:             * 
283:             * @param the filter to be visited
284:             */
285:            public Object visit(ExcludeFilter filter, Object extraData) {
286:                try {
287:                    out.write("FALSE");
288:                } catch (IOException ioe) {
289:                    throw new RuntimeException(IO_ERROR, ioe);
290:                }
291:                return extraData;
292:            }
293:
294:            /**
295:             * @see {@link FilterVisitor#visit(IncludeFilter, Object)}
296:             * 
297:             * Writes the SQL for the IncludeFilter by writing "TRUE".
298:             * 
299:             * @param the filter to be visited
300:             *  
301:             */
302:            public Object visit(IncludeFilter filter, Object extraData) {
303:                try {
304:                    out.write("TRUE");
305:                } catch (IOException ioe) {
306:                    throw new RuntimeException(IO_ERROR, ioe);
307:                }
308:                return extraData;
309:            }
310:
311:            /**
312:             * Writes the SQL for the PropertyIsBetween Filter.
313:             *
314:             * @param filter the Filter to be visited.
315:             *
316:             * @throws RuntimeException for io exception with writer
317:             */
318:            public Object visit(PropertyIsBetween filter, Object extraData)
319:                    throws RuntimeException {
320:                LOGGER.finer("exporting PropertyIsBetween");
321:
322:                Expression expr = (Expression) filter.getExpression();
323:                Expression lowerbounds = (Expression) filter.getLowerBoundary();
324:                Expression upperbounds = (Expression) filter.getUpperBoundary();
325:
326:                Class context;
327:                AttributeType attType = (AttributeType) expr
328:                        .evaluate(featureType);
329:                if (attType != null) {
330:                    context = attType.getType();
331:                } else {
332:                    //assume it's a string?
333:                    context = String.class;
334:                }
335:
336:                try {
337:                    expr.accept(this , extraData);
338:                    out.write(" BETWEEN ");
339:                    lowerbounds.accept(this , context);
340:                    out.write(" AND ");
341:                    upperbounds.accept(this , context);
342:                } catch (java.io.IOException ioe) {
343:                    throw new RuntimeException(IO_ERROR, ioe);
344:                }
345:                return extraData;
346:            }
347:
348:            /**
349:             * Writes the SQL for the Like Filter.  Assumes the current java
350:             * implemented wildcards for the Like Filter: . for multi and .? for
351:             * single. And replaces them with the SQL % and _, respectively.
352:             *
353:             * @param filter the Like Filter to be visited.
354:             *
355:             * @task REVISIT: Need to think through the escape char, so it works  right
356:             *       when Java uses one, and escapes correctly with an '_'.
357:             */
358:            public Object visit(PropertyIsLike filter, Object extraData) {
359:                char esc = filter.getEscape().charAt(0);
360:                char multi = filter.getWildCard().charAt(0);
361:                char single = filter.getSingleChar().charAt(0);
362:                String pattern = LikeFilterImpl.convertToSQL92(esc, multi,
363:                        single, filter.getLiteral());
364:
365:                Expression att = filter.getExpression();
366:
367:                try {
368:                    att.accept(this , extraData);
369:                    out.write(" LIKE '");
370:                    out.write(pattern);
371:                    out.write("' ");
372:                } catch (java.io.IOException ioe) {
373:                    throw new RuntimeException(IO_ERROR, ioe);
374:                }
375:                return extraData;
376:            }
377:
378:            /**
379:             * Write the SQL for an And filter
380:             * 
381:             * @param filter the filter to visit
382:             * @param extraData extra data (unused by this method)
383:             * 
384:             */
385:            public Object visit(And filter, Object extraData) {
386:                return visit((BinaryLogicOperator) filter, "AND");
387:            }
388:
389:            /**
390:             * Write the SQL for a Not filter
391:             * 
392:             * @param filter the filter to visit
393:             * @param extraData extra data (unused by this method)
394:             * 
395:             */
396:            public Object visit(Not filter, Object extraData) {
397:                return visit((BinaryLogicOperator) filter, "NOT");
398:            }
399:
400:            /**
401:             * Write the SQL for an Or filter
402:             * 
403:             * @param filter the filter to visit
404:             * @param extraData extra data (unused by this method)
405:             * 
406:             */
407:            public Object visit(Or filter, Object extraData) {
408:                return visit((BinaryLogicOperator) filter, "OR");
409:            }
410:
411:            /**
412:             * Common implementation for BinaryLogicOperator filters.  This way
413:             * they're all handled centrally.
414:             *
415:             * @param filter the logic statement to be turned into SQL.
416:             * @param extraData extra filter data.  Not modified directly by this method.
417:             */
418:            protected Object visit(BinaryLogicOperator filter, Object extraData) {
419:                LOGGER.finer("exporting LogicFilter");
420:
421:                String type = (String) extraData;
422:
423:                try {
424:                    java.util.Iterator list = filter.getChildren().iterator();
425:
426:                    if (filter instanceof  Not) {
427:                        out.write(type + " (");
428:                        ((Filter) list.next()).accept(this , extraData);
429:                        out.write(")");
430:                    } else { //AND or OR
431:                        out.write("(");
432:
433:                        while (list.hasNext()) {
434:                            ((Filter) list.next()).accept(this , extraData);
435:
436:                            if (list.hasNext()) {
437:                                out.write(" " + type + " ");
438:                            }
439:                        }
440:
441:                        out.write(")");
442:                    }
443:                } catch (java.io.IOException ioe) {
444:                    throw new RuntimeException(IO_ERROR, ioe);
445:                }
446:                return extraData;
447:            }
448:
449:            /**
450:             * Write the SQL for this kind of filter
451:             * 
452:             * @param filter the filter to visit
453:             * @param extraData extra data (unused by this method)
454:             * 
455:             */
456:            public Object visit(PropertyIsEqualTo filter, Object extraData) {
457:                visitBinaryComparisonOperator(
458:                        (BinaryComparisonOperator) filter, "=");
459:                return extraData;
460:            }
461:
462:            /**
463:             * Write the SQL for this kind of filter
464:             * 
465:             * @param filter the filter to visit
466:             * @param extraData extra data (unused by this method)
467:             * 
468:             */
469:            public Object visit(PropertyIsGreaterThanOrEqualTo filter,
470:                    Object extraData) {
471:                visitBinaryComparisonOperator(
472:                        (BinaryComparisonOperator) filter, ">=");
473:                return extraData;
474:            }
475:
476:            /**
477:             * Write the SQL for this kind of filter
478:             * 
479:             * @param filter the filter to visit
480:             * @param extraData extra data (unused by this method)
481:             * 
482:             */
483:            public Object visit(PropertyIsGreaterThan filter, Object extraData) {
484:                visitBinaryComparisonOperator(
485:                        (BinaryComparisonOperator) filter, ">");
486:                return extraData;
487:            }
488:
489:            /**
490:             * Write the SQL for this kind of filter
491:             * 
492:             * @param filter the filter to visit
493:             * @param extraData extra data (unused by this method)
494:             * 
495:             */
496:            public Object visit(PropertyIsLessThan filter, Object extraData) {
497:                visitBinaryComparisonOperator(
498:                        (BinaryComparisonOperator) filter, "<");
499:                return extraData;
500:            }
501:
502:            /**
503:             * Write the SQL for this kind of filter
504:             * 
505:             * @param filter the filter to visit
506:             * @param extraData extra data (unused by this method)
507:             * 
508:             */
509:            public Object visit(PropertyIsLessThanOrEqualTo filter,
510:                    Object extraData) {
511:                visitBinaryComparisonOperator(
512:                        (BinaryComparisonOperator) filter, "<=");
513:                return extraData;
514:            }
515:
516:            /**
517:             * Write the SQL for this kind of filter
518:             * 
519:             * @param filter the filter to visit
520:             * @param extraData extra data (unused by this method)
521:             * 
522:             */
523:            public Object visit(PropertyIsNotEqualTo filter, Object extraData) {
524:                visitBinaryComparisonOperator(
525:                        (BinaryComparisonOperator) filter, "!=");
526:                return extraData;
527:            }
528:
529:            /**
530:             * Common implementation for BinaryComparisonOperator filters.  This way
531:             * they're all handled centrally.
532:             *  
533:             *  DJB: note, postgis overwrites this implementation because of the way
534:             *       null is handled.  This is for <PropertyIsNull> filters and <PropertyIsEqual> filters
535:             *       are handled.  They will come here with "property = null".  
536:             *       NOTE: 
537:             *        SELECT * FROM <table> WHERE <column> isnull;  -- postgresql
538:             *        SELECT * FROM <table> WHERE isnull(<column>); -- oracle???
539:             *
540:             * @param filter the comparison to be turned into SQL.
541:             *
542:             * @throws RuntimeException for io exception with writer
543:             */
544:            protected void visitBinaryComparisonOperator(
545:                    BinaryComparisonOperator filter, Object extraData)
546:                    throws RuntimeException {
547:                LOGGER.finer("exporting SQL ComparisonFilter");
548:
549:                Expression left = filter.getExpression1();
550:                Expression right = filter.getExpression2();
551:                Class leftContext = null, rightContext = null;
552:                if (left instanceof  PropertyName) {
553:                    // aha!  It's a propertyname, we should get the class and pass it in
554:                    // as context to the tree walker.
555:                    AttributeType attType = (AttributeType) left
556:                            .evaluate(featureType);
557:                    if (attType != null) {
558:                        rightContext = attType.getType();
559:                    }
560:                }
561:
562:                if (right instanceof  PropertyName) {
563:                    AttributeType attType = (AttributeType) right
564:                            .evaluate(featureType);
565:                    if (attType != null) {
566:                        leftContext = attType.getType();
567:                    }
568:                }
569:
570:                String type = (String) extraData;
571:
572:                try {
573:                    left.accept(this , leftContext);
574:                    out.write(" " + type + " ");
575:                    right.accept(this , rightContext);
576:                } catch (java.io.IOException ioe) {
577:                    throw new RuntimeException(IO_ERROR, ioe);
578:                }
579:            }
580:
581:            /**
582:             * Writes the SQL for the Null Filter.
583:             *
584:             * @param filter the null filter to be written to SQL.
585:             *
586:             * @throws RuntimeException for io exception with writer
587:             */
588:            public Object visit(PropertyIsNull filter, Object extraData)
589:                    throws RuntimeException {
590:                LOGGER.finer("exporting NullFilter");
591:
592:                Expression expr = filter.getExpression();
593:
594:                try {
595:                    expr.accept(this , extraData);
596:                    out.write(" IS NULL ");
597:                } catch (java.io.IOException ioe) {
598:                    throw new RuntimeException(IO_ERROR, ioe);
599:                }
600:                return extraData;
601:            }
602:
603:            /**
604:             * Encodes an Id filter
605:             *
606:             * @param filter the
607:             *
608:             * @throws RuntimeException If there's a problem writing output
609:             *
610:             */
611:            public Object visit(Id filter, Object extraData) {
612:                if (mapper == null) {
613:                    throw new RuntimeException(
614:                            "Must set a fid mapper before trying to encode FIDFilters");
615:                }
616:
617:                FeatureId[] fids = (FeatureId[]) filter.getIdentifiers()
618:                        .toArray();
619:                LOGGER.finer("Exporting FID=" + Arrays.asList(fids));
620:
621:                // prepare column name array
622:                String[] colNames = new String[mapper.getColumnCount()];
623:
624:                for (int i = 0; i < colNames.length; i++) {
625:                    colNames[i] = mapper.getColumnName(i);
626:                }
627:
628:                for (int i = 0; i < fids.length; i++) {
629:                    try {
630:                        Object[] attValues = mapper.getPKAttributes(fids[i]
631:                                .getID());
632:
633:                        out.write("(");
634:
635:                        for (int j = 0; j < attValues.length; j++) {
636:                            out.write(escapeName(colNames[j]));
637:                            out.write(" = '");
638:                            out.write(attValues[j].toString()); //DJB: changed this to attValues[j] from attValues[i].
639:                            out.write("'");
640:
641:                            if (j < (attValues.length - 1)) {
642:                                out.write(" AND ");
643:                            }
644:                        }
645:
646:                        out.write(")");
647:
648:                        if (i < (fids.length - 1)) {
649:                            out.write(" OR ");
650:                        }
651:                    } catch (java.io.IOException e) {
652:                        throw new RuntimeException(IO_ERROR, e);
653:                    }
654:                }
655:
656:                return extraData;
657:            }
658:
659:            public Object visit(BBOX filter, Object extraData) {
660:                return visitBinarySpatialOperator(
661:                        (BinarySpatialOperator) filter, extraData);
662:            }
663:
664:            public Object visit(Beyond filter, Object extraData) {
665:                return visitBinarySpatialOperator(
666:                        (BinarySpatialOperator) filter, extraData);
667:            }
668:
669:            public Object visit(Contains filter, Object extraData) {
670:                return visitBinarySpatialOperator(
671:                        (BinarySpatialOperator) filter, extraData);
672:            }
673:
674:            public Object visit(Crosses filter, Object extraData) {
675:                return visitBinarySpatialOperator(
676:                        (BinarySpatialOperator) filter, extraData);
677:            }
678:
679:            public Object visit(Disjoint filter, Object extraData) {
680:                return visitBinarySpatialOperator(
681:                        (BinarySpatialOperator) filter, extraData);
682:            }
683:
684:            public Object visit(DWithin filter, Object extraData) {
685:                return visitBinarySpatialOperator(
686:                        (BinarySpatialOperator) filter, extraData);
687:            }
688:
689:            public Object visit(Equals filter, Object extraData) {
690:                return visitBinarySpatialOperator(
691:                        (BinarySpatialOperator) filter, extraData);
692:            }
693:
694:            public Object visit(Intersects filter, Object extraData) {
695:                return visitBinarySpatialOperator(
696:                        (BinarySpatialOperator) filter, extraData);
697:            }
698:
699:            public Object visit(Overlaps filter, Object extraData) {
700:                return visitBinarySpatialOperator(
701:                        (BinarySpatialOperator) filter, extraData);
702:            }
703:
704:            public Object visit(Touches filter, Object extraData) {
705:                return visitBinarySpatialOperator(
706:                        (BinarySpatialOperator) filter, extraData);
707:            }
708:
709:            public Object visit(Within filter, Object extraData) {
710:                return visitBinarySpatialOperator(
711:                        (BinarySpatialOperator) filter, extraData);
712:            }
713:
714:            /**
715:             * @see {@link FilterVisitor#visit()}
716:             */
717:            protected Object visitBinarySpatialOperator(
718:                    BinarySpatialOperator filter, Object extraData) {
719:                throw new RuntimeException(
720:                        "Subclasses must implement this method in order to handle geometries");
721:            }
722:
723:            /**
724:             * Encodes a null filter value.  The current implementation
725:             * does exactly nothing.
726:             * @param extraData extra data to be used to evaluate the filter
727:             * @return the untouched extraData parameter
728:             */
729:            public Object visitNullFilter(Object extraData) {
730:                return extraData;
731:            }
732:
733:            // END IMPLEMENTING org.opengis.filter.FilterVisitor METHODS
734:
735:            // START IMPLEMENTING org.opengis.filter.ExpressionVisitor METHODS
736:
737:            /**
738:             * Writes the SQL for the attribute Expression.
739:             * 
740:             * NOTE:  This (default) implementation doesn't handle XPath at all.
741:             * Not sure exactly how to do that in a general way.  How to map from the XPATH of the
742:             * property name into a column or something?  Use propertyName.evaluate()?
743:             *
744:             * @param expression the attribute to turn to SQL.
745:             *
746:             * @throws RuntimeException for io exception with writer
747:             */
748:            public Object visit(PropertyName expression, Object extraData)
749:                    throws RuntimeException {
750:                LOGGER.finer("exporting PropertyName");
751:
752:                try {
753:                    out.write(escapeName(expression.getPropertyName()));
754:                } catch (java.io.IOException ioe) {
755:                    throw new RuntimeException(
756:                            "IO problems writing attribute exp", ioe);
757:                }
758:                return extraData;
759:            }
760:
761:            /**
762:             * Export the contents of a Literal Expresion
763:             *
764:             * @param expression the Literal to export
765:             *
766:             * @throws RuntimeException for io exception with writer
767:             */
768:            public Object visit(Literal expression, Object context)
769:                    throws RuntimeException {
770:                LOGGER.finer("exporting LiteralExpression");
771:
772:                //type to convert the literal to
773:                Class target = (Class) context;
774:
775:                try {
776:                    Object literal = null;
777:
778:                    if (target == Geometry.class
779:                            && expression.getValue() instanceof  Geometry) {
780:                        //call this method for backwards compatability with subclasses
781:                        visitLiteralGeometry(expression);
782:                        return context;
783:                    } else if (target != null) {
784:                        //convert the literal to the required type
785:                        //JD except for numerics, let the database do the converstion
786:
787:                        if (Number.class.isAssignableFrom(target)) {
788:                            //dont convert
789:                        } else {
790:                            //convert
791:                            literal = expression.evaluate(null, target);
792:                        }
793:
794:                        if (literal == null) {
795:                            //just use string
796:                            literal = expression.getValue().toString();
797:                        }
798:
799:                        //geometry hook
800:                        //if ( literal instanceof Geometry ) {
801:                        if (Geometry.class.isAssignableFrom(target)) {
802:                            visitLiteralGeometry(expression);
803:                        }
804:                        //else if ( literal instanceof Number ) {
805:                        else if (Number.class.isAssignableFrom(target)) {
806:                            out.write(literal.toString());
807:                        }
808:                        //else if ( literal instanceof String ) {
809:                        else if (String.class.isAssignableFrom(target)) {
810:                            // sigle quotes must be escaped to have a valid sql string
811:                            String escaped = literal.toString().replaceAll("'",
812:                                    "''");
813:                            out.write("'" + escaped + "'");
814:                        }
815:                    } else {
816:                        //convert back to a string
817:                        String encoding = (String) Converters.convert(literal,
818:                                String.class, null);
819:                        if (encoding == null) {
820:                            //could not convert back to string, use original l value
821:                            encoding = expression.getValue().toString();
822:                        }
823:
824:                        // sigle quotes must be escaped to have a valid sql string
825:                        String escaped = encoding.replaceAll("'", "''");
826:                        out.write("'" + escaped + "'");
827:                    }
828:
829:                } catch (IOException e) {
830:                    throw new RuntimeException("IO problems writing literal", e);
831:                }
832:                return context;
833:            }
834:
835:            /**
836:             * Subclasses must implement this method in order to encode geometry
837:             * filters according to the specific database implementation
838:             *
839:             * @param expression
840:             *
841:             * @throws IOException DOCUMENT ME!
842:             * @throws RuntimeException DOCUMENT ME!
843:             */
844:            protected void visitLiteralGeometry(Literal expression)
845:                    throws IOException {
846:                throw new RuntimeException(
847:                        "Subclasses must implement this method in order to handle geometries");
848:            }
849:
850:            public Object visit(Add expression, Object extraData) {
851:                return visit((BinaryExpression) expression, extraData);
852:            }
853:
854:            public Object visit(Divide expression, Object extraData) {
855:                return visit((BinaryExpression) expression, extraData);
856:            }
857:
858:            public Object visit(Multiply expression, Object extraData) {
859:                return visit((BinaryExpression) expression, extraData);
860:            }
861:
862:            public Object visit(Subtract expression, Object extraData) {
863:                return visit((BinaryExpression) expression, extraData);
864:            }
865:
866:            /**
867:             * Writes the SQL for the Math Expression.
868:             *
869:             * @param expression the Math phrase to be written.
870:             *
871:             * @throws RuntimeException for io problems
872:             */
873:            protected Object visit(BinaryExpression expression, Object extraData)
874:                    throws RuntimeException {
875:                LOGGER.finer("exporting Expression Math");
876:
877:                String type = (String) expressions.get(expression.getClass());
878:
879:                try {
880:                    expression.getExpression1().accept(this , extraData);
881:                    out.write(" " + type + " ");
882:                    expression.getExpression2().accept(this , extraData);
883:                } catch (java.io.IOException ioe) {
884:                    throw new RuntimeException(
885:                            "IO problems writing expression", ioe);
886:                }
887:                return extraData;
888:            }
889:
890:            /**
891:             * Writes sql for a function expression.  Not currently supported.
892:             *
893:             * @param expression a function expression
894:             *
895:             * @throws UnsupportedOperationException every time, this isn't supported.
896:             */
897:            public Object visit(Function expression, Object extraData)
898:                    throws UnsupportedOperationException {
899:                String message = "Function expression support not yet added.";
900:                throw new UnsupportedOperationException(message);
901:            }
902:
903:            public Object visit(NilExpression expression, Object extraData) {
904:                try {
905:                    out.write(" ");
906:                } catch (java.io.IOException ioe) {
907:                    throw new RuntimeException(
908:                            "IO problems writing expression", ioe);
909:                }
910:
911:                return extraData;
912:            }
913:
914:            /**
915:             * Sets the SQL name escape string.
916:             * 
917:             * <p>
918:             * The value of this string is prefixed and appended to table schema names,
919:             * table names and column names in an SQL statement to support mixed-case
920:             * and non-English names. Without this, the DBMS may assume a mixed-case
921:             * name in the query should be treated as upper-case and an SQLCODE of
922:             * -204 or 206 may result if the name is not found.
923:             * </p>
924:             * 
925:             * <p>
926:             * Typically this is the double-quote character, ", but may not be for all
927:             * databases.
928:             * </p>
929:             * 
930:             * <p>
931:             * For example, consider the following query:
932:             * </p>
933:             * 
934:             * <p>
935:             * SELECT Geom FROM Spear.ArchSites May be interpreted by the database as:
936:             * SELECT GEOM FROM SPEAR.ARCHSITES  If the column and table names were
937:             * actually created using mixed-case, the query needs to be specified as:
938:             * SELECT "Geom" from "Spear"."ArchSites"
939:             * </p>
940:             *
941:             * @param escape the character to be used to escape database names
942:             */
943:            public void setSqlNameEscape(String escape) {
944:                sqlNameEscape = escape;
945:            }
946:
947:            /**
948:             * Surrounds a name with the SQL escape character.
949:             *
950:             * @param name
951:             *
952:             * @return DOCUMENT ME!
953:             */
954:            public String escapeName(String name) {
955:                return sqlNameEscape + name + sqlNameEscape;
956:            }
957:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.