Source Code Cross Referenced for Element.java in  » GIS » GeoTools-2.4.1 » org » geotools » referencing » wkt » 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.referencing.wkt 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *   
005:         *   (C) 2003-2006, Geotools Project Managment Committee (PMC)
006:         *   (C) 2002, Institut de Recherche pour le Développement
007:         *
008:         *    This library is free software; you can redistribute it and/or
009:         *    modify it under the terms of the GNU Lesser General Public
010:         *    License as published by the Free Software Foundation; either
011:         *    version 2.1 of the License, or (at your option) any later version.
012:         *
013:         *    This library is distributed in the hope that it will be useful,
014:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
015:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
016:         *    Lesser General Public License for more details.
017:         */
018:        package org.geotools.referencing.wkt;
019:
020:        // Collections
021:        import java.io.PrintWriter;
022:        import java.text.ParseException;
023:        import java.text.ParsePosition;
024:        import java.util.Iterator;
025:        import java.util.LinkedList;
026:        import java.util.List;
027:
028:        // Geotools dependencies
029:        import org.geotools.resources.Utilities;
030:        import org.geotools.resources.XArray;
031:        import org.geotools.resources.i18n.Errors;
032:        import org.geotools.resources.i18n.ErrorKeys;
033:
034:        /**
035:         * An element in a <cite>Well Know Text</cite> (WKT). A {@code Element} is
036:         * made of {@link String}, {@link Number} and other {@link Element}. For example:
037:         *
038:         * <blockquote><pre>
039:         * PRIMEM["Greenwich", 0.0, AUTHORITY["some authority", "Greenwich"]]
040:         * </pre></blockquote>
041:         *
042:         * Each {@code Element} object can contains an arbitrary amount of other elements.
043:         * The result is a tree, which can be printed with {@link #print}.
044:         * Elements can be pull in a <cite>first in, first out</cite> order.
045:         *
046:         * @since 2.0
047:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/wkt/Element.java $
048:         * @version $Id: Element.java 21289 2006-08-30 10:52:24Z desruisseaux $
049:         * @author Remi Eve
050:         * @author Martin Desruisseaux
051:         */
052:        public final class Element {
053:            /**
054:             * The position where this element starts in the string to be parsed.
055:             */
056:            private final int offset;
057:
058:            /**
059:             * Keyword of this entity. For example: "PRIMEM".
060:             */
061:            public final String keyword;
062:
063:            /**
064:             * An ordered list of {@link String}s, {@link Number}s and other {@link Element}s.
065:             * May be {@code null} if the keyword was not followed by a pair of brackets
066:             * (e.g. "NORTH").
067:             */
068:            private final List list;
069:
070:            /**
071:             * Constructs a root element.
072:             *
073:             * @param singleton The only children for this root.
074:             */
075:            Element(final Element singleton) {
076:                offset = 0;
077:                keyword = null;
078:                list = new LinkedList();
079:                list.add(singleton);
080:            }
081:
082:            /**
083:             * Constructs a new {@code Element}.
084:             *
085:             * @param  text       The text to parse.
086:             * @param  position   In input, the position where to start parsing from.
087:             *                    In output, the first character after the separator.
088:             */
089:            Element(final AbstractParser parser, final String text,
090:                    final ParsePosition position) throws ParseException {
091:                /*
092:                 * Find the first keyword in the specified string. If a keyword is found, then
093:                 * the position is set to the index of the first character after the keyword.
094:                 */
095:                int lower = position.getIndex();
096:                final int length = text.length();
097:                while (lower < length
098:                        && Character.isWhitespace(text.charAt(lower))) {
099:                    lower++;
100:                }
101:                offset = lower;
102:                int upper = lower;
103:                while (upper < length
104:                        && Character
105:                                .isUnicodeIdentifierPart(text.charAt(upper))) {
106:                    upper++;
107:                }
108:                if (upper <= lower) {
109:                    position.setErrorIndex(lower);
110:                    throw unparsableString(text, position);
111:                }
112:                keyword = text.substring(lower, upper).toUpperCase(
113:                        parser.symbols.locale);
114:                position.setIndex(upper);
115:                /*
116:                 * Parse the opening bracket. According CTS's specification, two characters
117:                 * are acceptable: '[' and '('.  At the end of this method, we will require
118:                 * the matching closing bracket. For example if the opening bracket was '[',
119:                 * then we will require that the closing bracket is ']' and not ')'.
120:                 */
121:                int bracketIndex = -1;
122:                do {
123:                    if (++bracketIndex >= parser.symbols.openingBrackets.length) {
124:                        list = null;
125:                        return;
126:                    }
127:                } while (!parseOptionalSeparator(text, position,
128:                        parser.symbols.openingBrackets[bracketIndex]));
129:                list = new LinkedList();
130:                /*
131:                 * Parse all elements inside the bracket. Elements are parsed sequentially
132:                 * and their type are selected according their first character:
133:                 *
134:                 *   - If the first character is a quote, then the element is parsed as a String.
135:                 *   - Otherwise, if the first character is a unicode identifier start, then the
136:                 *     element is parsed as a chidren Element.
137:                 *   - Otherwise, the element is parsed as a number.
138:                 */
139:                do {
140:                    if (position.getIndex() >= length) {
141:                        throw missingCharacter(parser.symbols.close, length);
142:                    }
143:                    //
144:                    // Try to parse the next element as a quoted string. We will take
145:                    // it as a string if the first non-blank character is a quote.
146:                    //
147:                    if (parseOptionalSeparator(text, position,
148:                            parser.symbols.quote)) {
149:                        lower = position.getIndex();
150:                        upper = text.indexOf(parser.symbols.quote, lower);
151:                        if (upper < lower) {
152:                            position.setErrorIndex(++lower);
153:                            throw missingCharacter(parser.symbols.quote, lower);
154:                        }
155:                        list.add(text.substring(lower, upper).trim());
156:                        position.setIndex(upper + 1);
157:                        continue;
158:                    }
159:                    //
160:                    // Try to parse the next element as a number. We will take it as a number if
161:                    // the first non-blank character is not the begining of an unicode identifier.
162:                    //
163:                    lower = position.getIndex();
164:                    if (!Character.isUnicodeIdentifierStart(text.charAt(lower))) {
165:                        final Number number = parser
166:                                .parseNumber(text, position);
167:                        if (number == null) {
168:                            // Do not update the error index; it is already updated by NumberFormat.
169:                            throw unparsableString(text, position);
170:                        }
171:                        list.add(number);
172:                        continue;
173:                    }
174:                    // Otherwise, add the element as a child element.
175:                    list.add(new Element(parser, text, position));
176:                } while (parseOptionalSeparator(text, position,
177:                        parser.symbols.separator));
178:                parseSeparator(text, position,
179:                        parser.symbols.closingBrackets[bracketIndex]);
180:            }
181:
182:            /**
183:             * Returns {@code true} if the next non-whitespace character is the specified separator.
184:             * Search is performed in string {@code text} from position {@code position}. If the
185:             * separator is found, then the position is set to the first character after the separator.
186:             * Otherwise, the position is set on the first non-blank character.
187:             *
188:             * @param  text       The text to parse.
189:             * @param  position   In input, the position where to start parsing from.
190:             *                    In output, the first character after the separator.
191:             * @param  separator  The character to search.
192:             * @return {@code true} if the next non-whitespace character is the separator,
193:             *         or {@code false} otherwise.
194:             */
195:            private static boolean parseOptionalSeparator(final String text,
196:                    final ParsePosition position, final char separator) {
197:                final int length = text.length();
198:                int index = position.getIndex();
199:                while (index < length) {
200:                    final char c = text.charAt(index);
201:                    if (Character.isWhitespace(c)) {
202:                        index++;
203:                        continue;
204:                    }
205:                    if (c == separator) {
206:                        position.setIndex(++index);
207:                        return true;
208:                    }
209:                    break;
210:                }
211:                position.setIndex(index); // MANDATORY for correct working of the constructor.
212:                return false;
213:            }
214:
215:            /**
216:             * Moves to the next non-whitespace character and checks if this character is the
217:             * specified separator. If the separator is found, it is skipped. Otherwise, this
218:             * method thrown a {@link ParseException}.
219:             *
220:             * @param  text       The text to parse.
221:             * @param  position   In input, the position where to start parsing from.
222:             *                    In output, the first character after the separator.
223:             * @param  separator  The character to search.
224:             * @throws ParseException if the separator was not found.
225:             */
226:            private void parseSeparator(final String text,
227:                    final ParsePosition position, final char separator)
228:                    throws ParseException {
229:                if (!parseOptionalSeparator(text, position, separator)) {
230:                    position.setErrorIndex(position.getIndex());
231:                    throw unparsableString(text, position);
232:                }
233:            }
234:
235:            //////////////////////////////////////////////////////////////////////////////////////
236:            ////////                                                                      ////////
237:            ////////    Construction of a ParseException when a string can't be parsed    ////////
238:            ////////                                                                      ////////
239:            //////////////////////////////////////////////////////////////////////////////////////
240:            /**
241:             * Returns a {@link ParseException} with the specified cause. A localized string
242:             * <code>"Error in <{@link #keyword}>"</code> will be prepend to the message.
243:             * The error index will be the starting index of this {@code Element}.
244:             *
245:             * @param  cause   The cause of the failure, or {@code null} if none.
246:             * @param  message The message explaining the cause of the failure, or {@code null}
247:             *                 for reusing the same message than {@code cause}.
248:             * @return The exception to be thrown.
249:             */
250:            public ParseException parseFailed(final Exception cause,
251:                    String message) {
252:                if (message == null) {
253:                    message = cause.getLocalizedMessage();
254:                }
255:                ParseException exception = new ParseException(
256:                        complete(message), offset);
257:                exception = trim("parseFailed", exception);
258:                exception.initCause(cause);
259:                return exception;
260:            }
261:
262:            /**
263:             * Returns a {@link ParseException} with a "Unparsable string" message. The error message
264:             * is built from the specified string starting at the specified position. Properties
265:             * {@link ParsePosition#getIndex} and {@link ParsePosition#getErrorIndex} must be accurate
266:             * before this method is invoked.
267:             *
268:             * @param  text The unparsable string.
269:             * @param  position The position in the string.
270:             * @return An exception with a formatted error message.
271:             */
272:            private ParseException unparsableString(final String text,
273:                    final ParsePosition position) {
274:                final int lower = position.getErrorIndex();
275:                int upper = lower;
276:                final int length = text.length();
277:                if (upper < length) {
278:                    final int type = Character.getType(text.charAt(upper));
279:                    while (++upper < length) {
280:                        if (Character.getType(text.charAt(upper)) != type) {
281:                            break;
282:                        }
283:                    }
284:                }
285:                final String message;
286:                if (lower == length) {
287:                    message = Errors.format(ErrorKeys.UNEXPECTED_END_OF_STRING);
288:                } else {
289:                    message = Errors.format(ErrorKeys.UNPARSABLE_STRING_$2,
290:                            text.substring(position.getIndex()), text
291:                                    .substring(lower, upper));
292:                }
293:                return trim("unparsableString", new ParseException(
294:                        complete(message), lower));
295:            }
296:
297:            /**
298:             * Returns an exception saying that a character is missing.
299:             *
300:             * @param c The missing character.
301:             * @param position The error position.
302:             */
303:            private ParseException missingCharacter(final char c,
304:                    final int position) {
305:                return trim("missingCharacter", new ParseException(
306:                        complete(Errors.format(ErrorKeys.MISSING_CHARACTER_$1,
307:                                new Character(c))), position));
308:            }
309:
310:            /**
311:             * Returns an exception saying that a parameter is missing.
312:             *
313:             * @param key The name of the missing parameter.
314:             */
315:            private ParseException missingParameter(final String key) {
316:                int error = offset;
317:                if (keyword != null) {
318:                    error += keyword.length();
319:                }
320:                return trim("missingParameter", new ParseException(
321:                        complete(Errors.format(ErrorKeys.MISSING_PARAMETER_$1,
322:                                key)), error));
323:            }
324:
325:            /**
326:             * Append a prefix "Error in <keyword>: " before the error message.
327:             *
328:             * @param  message The message to complete.
329:             * @return The completed message.
330:             */
331:            private String complete(String message) {
332:                if (keyword != null) {
333:                    message = Errors.format(ErrorKeys.IN_$1, keyword) + ' '
334:                            + message;
335:                }
336:                return message;
337:            }
338:
339:            /**
340:             * Remove the exception factory method from the stack trace. The factory is
341:             * not the place where the failure occurs; the error occurs in the factory's
342:             * caller.
343:             *
344:             * @param  factory   The name of the factory method.
345:             * @param  exception The exception to trim.
346:             * @return {@code exception} for convenience.
347:             */
348:            private static ParseException trim(final String factory,
349:                    final ParseException exception) {
350:                StackTraceElement[] trace = exception.getStackTrace();
351:                if (trace != null && trace.length != 0) {
352:                    if (factory.equals(trace[0].getMethodName())) {
353:                        trace = (StackTraceElement[]) XArray
354:                                .remove(trace, 0, 1);
355:                        exception.setStackTrace(trace);
356:                    }
357:                }
358:                return exception;
359:            }
360:
361:            /**
362:             * Returns {@code true} if this element is the root element. For example in a WKT like
363:             * {@code "GEOGCS["name", DATUM["name, ...]]"}, this is true for {@code "GEOGCS"} and
364:             * false for all other elements inside, like {@code "DATUM"}.
365:             *
366:             * @since 2.3
367:             */
368:            public boolean isRoot() {
369:                return this .offset == 0;
370:            }
371:
372:            //////////////////////////////////////////////////////////////////////////////////////
373:            ////////                                                                      ////////
374:            ////////    Pull elements from the tree                                       ////////
375:            ////////                                                                      ////////
376:            //////////////////////////////////////////////////////////////////////////////////////
377:            /**
378:             * Removes the next {@link Number} from the list and returns it.
379:             *
380:             * @param  key The parameter name. Used for formatting
381:             *         an error message if no number are found.
382:             * @return The next {@link Number} on the list as a {@code double}.
383:             * @throws ParseException if no more number is available.
384:             */
385:            public double pullDouble(final String key) throws ParseException {
386:                final Iterator iterator = list.iterator();
387:                while (iterator.hasNext()) {
388:                    final Object object = iterator.next();
389:                    if (object instanceof  Number) {
390:                        iterator.remove();
391:                        return ((Number) object).doubleValue();
392:                    }
393:                }
394:                throw missingParameter(key);
395:            }
396:
397:            /**
398:             * Removes the next {@link Number} from the list and returns it
399:             * as an integer.
400:             *
401:             * @param  key The parameter name. Used for formatting
402:             *         an error message if no number are found.
403:             * @return The next {@link Number} on the list as an {@code int}.
404:             * @throws ParseException if no more number is available, or the number
405:             *         is not an integer.
406:             */
407:            public int pullInteger(final String key) throws ParseException {
408:                final Iterator iterator = list.iterator();
409:                while (iterator.hasNext()) {
410:                    final Object object = iterator.next();
411:                    if (object instanceof  Number) {
412:                        iterator.remove();
413:                        final Number number = (Number) object;
414:                        if (number instanceof  Float || number instanceof  Double) {
415:                            throw new ParseException(
416:                                    complete(Errors.format(
417:                                            ErrorKeys.ILLEGAL_ARGUMENT_$2, key,
418:                                            number)), offset);
419:                        }
420:                        return number.intValue();
421:                    }
422:                }
423:                throw missingParameter(key);
424:            }
425:
426:            /**
427:             * Removes the next {@link String} from the list and returns it.
428:             *
429:             * @param  key The parameter name. Used for formatting
430:             *         an error message if no number are found.
431:             * @return The next {@link String} on the list.
432:             * @throws ParseException if no more string is available.
433:             */
434:            public String pullString(final String key) throws ParseException {
435:                final Iterator iterator = list.iterator();
436:                while (iterator.hasNext()) {
437:                    final Object object = iterator.next();
438:                    if (object instanceof  String) {
439:                        iterator.remove();
440:                        return (String) object;
441:                    }
442:                }
443:                throw missingParameter(key);
444:            }
445:
446:            /**
447:             * Removes the next {@link Element} from the list and returns it.
448:             *
449:             * @param  key The element name (e.g. <code>"PRIMEM"</code>).
450:             * @return The next {@link Element} on the list.
451:             * @throws ParseException if no more element is available.
452:             */
453:            public Element pullElement(final String key) throws ParseException {
454:                final Element element = pullOptionalElement(key);
455:                if (element != null) {
456:                    return element;
457:                }
458:                throw missingParameter(key);
459:            }
460:
461:            /**
462:             * Removes the next {@link Element} from the list and returns it.
463:             *
464:             * @param  key The element name (e.g. <code>"PRIMEM"</code>).
465:             * @return The next {@link Element} on the list,
466:             *         or {@code null} if no more element is available.
467:             */
468:            public Element pullOptionalElement(String key) {
469:                key = key.toUpperCase();
470:                final Iterator iterator = list.iterator();
471:                while (iterator.hasNext()) {
472:                    final Object object = iterator.next();
473:                    if (object instanceof  Element) {
474:                        final Element element = (Element) object;
475:                        if (element.list != null && element.keyword.equals(key)) {
476:                            iterator.remove();
477:                            return element;
478:                        }
479:                    }
480:                }
481:                return null;
482:            }
483:
484:            /**
485:             * Removes and returns the next {@link Element} with no bracket.
486:             * The key is used only for only for formatting an error message.
487:             *
488:             * @param  key The parameter name. Used only for formatting an error message.
489:             * @return The next {@link Element} in the list, with no bracket.
490:             * @throws ParseException if no more void element is available.
491:             */
492:            public Element pullVoidElement(final String key)
493:                    throws ParseException {
494:                final Iterator iterator = list.iterator();
495:                while (iterator.hasNext()) {
496:                    final Object object = iterator.next();
497:                    if (object instanceof  Element) {
498:                        final Element element = (Element) object;
499:                        if (element.list == null) {
500:                            iterator.remove();
501:                            return element;
502:                        }
503:                    }
504:                }
505:                throw missingParameter(key);
506:            }
507:
508:            /**
509:             * Returns the next element, or {@code null} if there is no more
510:             * element. The element is <strong>not</strong> removed from the list.
511:             */
512:            public Object peek() {
513:                return list.isEmpty() ? null : list.get(0);
514:            }
515:
516:            /**
517:             * Close this element.
518:             *
519:             * @throws ParseException If the list still contains some unprocessed elements.
520:             */
521:            public void close() throws ParseException {
522:                if (list != null && !list.isEmpty()) {
523:                    throw new ParseException(complete(Errors.format(
524:                            ErrorKeys.UNEXPECTED_PARAMETER_$1, list.get(0))),
525:                            offset + keyword.length());
526:                }
527:            }
528:
529:            /**
530:             * Returns the keyword. This overriding is needed for correct
531:             * formatting of the error message in {@link #close}.
532:             */
533:            public String toString() {
534:                return keyword;
535:            }
536:
537:            /**
538:             * Print this {@code Element} as a tree.
539:             * This method is used for debugging purpose only.
540:             *
541:             * @param  out    The output stream.
542:             * @param  level  The indentation level (usually 0).
543:             */
544:            public void print(final PrintWriter out, final int level) {
545:                final int tabWidth = 4;
546:                out.print(Utilities.spaces(tabWidth * level));
547:                out.println(keyword);
548:                if (list == null) {
549:                    return;
550:                }
551:                final int size = list.size();
552:                for (int j = 0; j < size; j++) {
553:                    final Object object = list.get(j);
554:                    if (object instanceof  Element) {
555:                        ((Element) object).print(out, level + 1);
556:                    } else {
557:                        out.print(Utilities.spaces(tabWidth * (level + 1)));
558:                        out.println(object);
559:                    }
560:                }
561:            }
562:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.