New upstream version 2021.1.0
Bas Couwenberg
1 year, 9 months ago
0 | #!/usr/bin/env bash | |
1 | ||
2 | set -euf | |
3 | ||
4 | sudo apt-get update | |
5 | sudo apt-get install -y gnupg haveged | |
6 | ||
7 | rm -rf ~/.gnupg | |
8 | gpg --list-keys | |
9 | ||
10 | cat >key-info <<EOF | |
11 | %echo Generating a key | |
12 | Key-Type: RSA | |
13 | Key-Length: 4096 | |
14 | Subkey-Type: RSA | |
15 | Subkey-Length: 4096 | |
16 | Name-Real: PostGIS Development Team | |
17 | Name-Comment: PostGIS Development Team | |
18 | Name-Email: test-key@postgis.net | |
19 | Expire-Date: 0 | |
20 | %no-ask-passphrase | |
21 | %no-protection | |
22 | %commit | |
23 | %echo done | |
24 | EOF | |
25 | ||
26 | gpg --verbose --batch --gen-key key-info | |
27 | ||
28 | echo -e "5\ny\n" | gpg --no-tty --command-fd 0 --expert --edit-key test-key@postgis.net trust; | |
29 | ||
30 | # test | |
31 | gpg --list-keys | |
32 | gpg -e -a -r test-key@postgis.net key-info | |
33 | rm key-info | |
34 | gpg -d key-info.asc | |
35 | rm key-info.asc | |
36 | ||
37 | set +euf |
0 | #!/usr/bin/env bash | |
1 | ||
2 | set -euf | |
3 | ||
4 | MAVEN_BASE_URL=https://archive.apache.org/dist/maven/maven-3/ | |
5 | MAVEN_VERSION=3.8.1 | |
6 | MAVEN_SHA=b98a1905eb554d07427b2e5509ff09bd53e2f1dd7a0afa38384968b113abef02 | |
7 | ||
8 | sudo apt-get update | |
9 | sudo apt-get install -y curl | |
10 | sudo mkdir -p /usr/share/maven /usr/share/maven/ref | |
11 | sudo curl -fsSL -o /tmp/apache-maven.tar.gz ${MAVEN_BASE_URL}/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz | |
12 | echo "${MAVEN_SHA} /tmp/apache-maven.tar.gz" | sha256sum -c - | |
13 | sudo tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 | |
14 | sudo rm -f /tmp/apache-maven.tar.gz | |
15 | sudo ln -fs /usr/share/maven/bin/mvn /usr/bin/mvn | |
16 | mvn -version | |
17 | ||
18 | set +euf | |
19 |
0 | #!/usr/bin/env bash | |
1 | ||
2 | set -euf | |
3 | ||
4 | AZUL_GPG_KEY=0xB1998361219BD9C9 | |
5 | ZULU_VERSION=11 | |
6 | ZULU_RELEASE=11.0.12-1 | |
7 | ||
8 | sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys ${AZUL_GPG_KEY} | |
9 | sudo apt-add-repository 'deb http://repos.azulsystems.com/ubuntu stable main' | |
10 | sudo apt-get update | |
11 | sudo apt-get install -y zulu-repo | |
12 | sudo apt-get update | |
13 | sudo apt-get install -y zulu${ZULU_VERSION}=${ZULU_RELEASE} | |
14 | sudo sed -i.orig -e "s/^hl /jre /g" -e "s/^jdkhl /jdk /g" /usr/lib/jvm/.zulu${ZULU_VERSION}-ca-amd64.jinfo | |
15 | sudo update-java-alternatives --set zulu${ZULU_VERSION}-ca-amd64 | |
16 | export ALTERNATIVES_JAVAC=$(realpath /etc/alternatives/javac) | |
17 | export JAVA_HOME=${ALTERNATIVES_JAVAC%/bin/javac} | |
18 | export PATH=$JAVA_HOME/bin:$PATH | |
19 | java -version | |
20 | ||
21 | set +euf | |
22 |
0 | #!/usr/bin/env bash | |
1 | ||
2 | set -euf | |
3 | ||
4 | AZUL_GPG_KEY=0xB1998361219BD9C9 | |
5 | ZULU_VERSION=8 | |
6 | ZULU_RELEASE=8.0.302-1 | |
7 | ||
8 | sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys ${AZUL_GPG_KEY} | |
9 | sudo apt-add-repository 'deb http://repos.azulsystems.com/ubuntu stable main' | |
10 | sudo apt-get update | |
11 | sudo apt-get install -y zulu-repo | |
12 | sudo apt-get update | |
13 | sudo apt-get install -y zulu${ZULU_VERSION}=${ZULU_RELEASE} | |
14 | sudo sed -i.orig -e "s/^hl /jre /g" -e "s/^jdkhl /jdk /g" /usr/lib/jvm/.zulu${ZULU_VERSION}-ca-amd64.jinfo | |
15 | sudo update-java-alternatives --set zulu${ZULU_VERSION}-ca-amd64 | |
16 | export ALTERNATIVES_JAVAC=$(realpath /etc/alternatives/javac) | |
17 | export JAVA_HOME=${ALTERNATIVES_JAVAC%/bin/javac} | |
18 | export PATH=$JAVA_HOME/bin:$PATH | |
19 | java -version | |
20 | ||
21 | set +euf | |
22 |
0 | <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" | |
1 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
2 | xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> | |
3 | <servers> | |
4 | <server> | |
5 | <id>ossrh</id> | |
6 | <username>${env.OSSRHU}</username> | |
7 | <password>${env.OSSRHT}</password> | |
8 | </server> | |
9 | </servers> | |
10 | <profiles> | |
11 | <profile> | |
12 | <id>gpg</id> | |
13 | <properties> | |
14 | <gpg.keyname>test-key@postgis.net</gpg.keyname> | |
15 | </properties> | |
16 | </profile> | |
17 | <profile> | |
18 | <id>sonatype-snapshots</id> | |
19 | <repositories> | |
20 | <repository> | |
21 | <id>sonatype-snapshots</id> | |
22 | <snapshots> | |
23 | <enabled>true</enabled> | |
24 | </snapshots> | |
25 | <name>sonatype-snapshots</name> | |
26 | <url>https://oss.sonatype.org/content/repositories/snapshots/</url> | |
27 | </repository> | |
28 | </repositories> | |
29 | </profile> | |
30 | <profile> | |
31 | <id>sonatype-staging</id> | |
32 | <repositories> | |
33 | <repository> | |
34 | <id>sonatype-staging</id> | |
35 | <snapshots> | |
36 | <enabled>true</enabled> | |
37 | </snapshots> | |
38 | <name>sonatype-staging</name> | |
39 | <url>https://oss.sonatype.org/content/groups/staging/</url> | |
40 | </repository> | |
41 | </repositories> | |
42 | </profile> | |
43 | <profile> | |
44 | <id>sonatype-releases</id> | |
45 | <repositories> | |
46 | <repository> | |
47 | <id>sonatype-releases</id> | |
48 | <snapshots> | |
49 | <enabled>true</enabled> | |
50 | </snapshots> | |
51 | <name>sonatype-releases</name> | |
52 | <url>https://oss.sonatype.org/content/groups/public/</url> | |
53 | </repository> | |
54 | </repositories> | |
55 | </profile> | |
56 | </profiles> | |
57 | ||
58 | </settings> |
0 | name: PostGIS Java CI | |
1 | ||
2 | on: [push, pull_request] | |
3 | ||
4 | defaults: | |
5 | run: | |
6 | shell: bash | |
7 | ||
8 | jobs: | |
9 | build-codebase: | |
10 | strategy: | |
11 | matrix: | |
12 | os: [ubuntu-20.04] | |
13 | java_version: [8] | |
14 | maven_version: [3.8.1] | |
15 | include: | |
16 | - os: ubuntu-20.04 | |
17 | java_version: 8 | |
18 | maven_version: 3.8.1 | |
19 | maven_deploy: true | |
20 | name: Build on OS ${{ matrix.os }} with Maven ${{ matrix.maven_version }} using Zulu ${{ matrix.java_version }} | |
21 | runs-on: ${{ matrix.os }} | |
22 | env: | |
23 | JAVA_HOME: /usr/lib/jvm/zulu${{ matrix.java_version }}-ca-amd64 | |
24 | MAVEN_HOME: /usr/share/maven | |
25 | MAVEN_PROPS: -Djavadoc.path=`which javadoc` | |
26 | PROFILES: gpg,release-sign-artifacts,sonatype-deployment,sonatype-snapshots,sonatype-staging,sonatype-releases | |
27 | SETTINGS: .github/settings.xml | |
28 | ||
29 | steps: | |
30 | - name: Checkout Source | |
31 | uses: actions/checkout@v2 | |
32 | ||
33 | - name: Install GPG and generate test key | |
34 | run: .github/install-gpg.sh | |
35 | ||
36 | - name: Install Zulu OpenJDK | |
37 | run: .github/install-zulu${{ matrix.java_version }}.sh | |
38 | ||
39 | - name: Install Maven | |
40 | run: .github/install-maven.sh | |
41 | ||
42 | - name: Setup Maven repository cache | |
43 | uses: actions/cache@v2 | |
44 | env: | |
45 | cache-name: m2repo | |
46 | with: | |
47 | path: ~/.m2/repository | |
48 | key: ${{ env.cache-name }}-${{ hashFiles('**/pom.xml') }} | |
49 | restore-keys: | | |
50 | ${{ env.cache-name }}- | |
51 | ||
52 | - name: Log github.ref | |
53 | run: echo "${{ github.ref }}" | |
54 | ||
55 | - name: Show Maven dependency tree | |
56 | run: mvn -U -V -s ${{ env.SETTINGS }} -P${{ env.PROFILES }} ${{ env.MAVEN_PROPS }} dependency:tree | |
57 | ||
58 | - name: Show Maven active profiles | |
59 | run: mvn -U -V -s ${{ env.SETTINGS }} -P${{ env.PROFILES }} ${{ env.MAVEN_PROPS }} help:active-profiles | |
60 | ||
61 | - name: Show Maven effective POM | |
62 | run: mvn -U -V -s ${{ env.SETTINGS }} -P${{ env.PROFILES }} ${{ env.MAVEN_PROPS }} help:effective-pom | |
63 | ||
64 | - name: Maven build/test | |
65 | run: mvn -U -V -s ${{ env.SETTINGS }} -P${{ env.PROFILES }} ${{ env.MAVEN_PROPS }} clean install | |
66 | ||
67 | - name: Maven generate site | |
68 | run: mvn -U -V -s ${{ env.SETTINGS }} -P${{ env.PROFILES }} ${{ env.MAVEN_PROPS }} site site:stage | |
69 | ||
70 | - name: Maven deploy | |
71 | if: ${{ matrix.maven_deploy && (github.ref == 'refs/heads/main') && (github.event_name != 'pull_request') }} | |
72 | env: | |
73 | OSSRHU: ${{ secrets.OSSRHU }} | |
74 | OSSRHT: ${{ secrets.OSSRHT }} | |
75 | run: mvn -U -V -s ${{ env.SETTINGS }} -P${{ env.PROFILES }} ${{ env.MAVEN_PROPS }} deploy⏎ |
0 | #!/usr/bin/env bash | |
1 | ||
2 | set -euf | |
3 | ||
4 | MAVEN_BASE_URL=https://archive.apache.org/dist/maven/maven-3/ | |
5 | MAVEN_VERSION=3.6.3 | |
6 | MAVEN_SHA=26ad91d751b3a9a53087aefa743f4e16a17741d3915b219cf74112bf87a438c5 | |
7 | ||
8 | sudo apt-get update | |
9 | sudo apt-get install -y curl | |
10 | sudo mkdir -p /usr/share/maven /usr/share/maven/ref | |
11 | sudo curl -fsSL -o /tmp/apache-maven.tar.gz ${MAVEN_BASE_URL}/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz | |
12 | echo "${MAVEN_SHA} /tmp/apache-maven.tar.gz" | sha256sum -c - | |
13 | sudo tar -xzf /tmp/apache-maven.tar.gz -C /usr/share/maven --strip-components=1 | |
14 | sudo rm -f /tmp/apache-maven.tar.gz | |
15 | sudo ln -s /usr/share/maven/bin/mvn /usr/bin/mvn | |
16 | mvn -version | |
17 | ||
18 | set +euf⏎ |
0 | #!/usr/bin/env bash | |
1 | ||
2 | set -euf | |
3 | ||
4 | AZUL_GPG_KEY=0xB1998361219BD9C9 | |
5 | ZULU_VERSION=11 | |
6 | ZULU_RELEASE=11.37+17 | |
7 | JAVA_HOME=/usr/lib/jvm/zulu-11-amd64 | |
8 | ||
9 | sudo apt-get update | |
10 | sudo apt-get install -y gnupg2 locales | |
11 | sudo locale-gen en_US.UTF-8 | |
12 | sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys ${AZUL_GPG_KEY} | |
13 | echo "deb http://repos.azulsystems.com/ubuntu stable main" | sudo tee -a /etc/apt/sources.list.d/zulu.list | |
14 | sudo apt-get update | |
15 | sudo apt-get install -y zulu-${ZULU_VERSION}=${ZULU_RELEASE} | |
16 | export ALTERNATIVES_JAVA=$(realpath /etc/alternatives/java) | |
17 | export JAVA_HOME=${ALTERNATIVES_JAVA%/bin/java} | |
18 | export PATH=$JAVA_HOME/bin:$PATH | |
19 | java -version | |
20 | ||
21 | set +euf⏎ |
0 | dist: xenial | |
1 | language: java | |
2 | services: docker | |
3 | ||
4 | install: | |
5 | - source .travis/install-zulu.sh | |
6 | - source .travis/install-maven.sh | |
7 | ||
8 | script: | |
9 | - mvn -U -V clean install |
0 | <?xml version="1.0"?> | |
1 | <!-- | |
2 | Copyright (c) 2016 Luminosity Labs LLC. All rights reserved. | |
3 | ||
4 | Licensed to the Apache Software Foundation (ASF) under one or more | |
5 | contributor license agreements. See the NOTICE file distributed with this | |
6 | work for additional information regarding copyright ownership. The ASF | |
7 | licenses this file to you under the Apache License, Version 2.0 | |
8 | (the "License"); you may not use this file except in compliance with the | |
9 | License. You may obtain a copy of the License at | |
10 | http://www.apache.org/licenses/LICENSE-2.0 | |
11 | Unless required by applicable law or agreed to in writing, software | |
12 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
13 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
14 | License for the specific language governing permissions and limitations | |
15 | under the License. | |
16 | --> | |
17 | <!DOCTYPE module PUBLIC | |
18 | "-//Puppy Crawl//DTD Check Configuration 1.3//EN" | |
19 | "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> | |
20 | <module name="Checker"> | |
21 | <!-- | |
22 | If you set the basedir property below, then all reported file | |
23 | names will be relative to the specified directory. See | |
24 | http://checkstyle.sourceforge.net/5.x/config.html#Checker | |
25 | <property name="basedir" value="${basedir}"/> | |
26 | --> | |
27 | ||
28 | <property name="fileExtensions" value="java, properties, xml"/> | |
29 | ||
30 | <!-- Enable suppression with @SuppressWarnings annotations--> | |
31 | <module name="SuppressWarningsFilter"/> | |
32 | ||
33 | <!-- Checks that a package-info.java file exists for each package. --> | |
34 | <!-- See http://checkstyle.sf.net/config_javadoc.html#JavadocPackage --> | |
35 | <module name="JavadocPackage"/> | |
36 | ||
37 | <!-- Checks whether files end with a new line. --> | |
38 | <!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile --> | |
39 | <module name="NewlineAtEndOfFile"/> | |
40 | ||
41 | <!-- Checks that property files contain the same keys. --> | |
42 | <!-- See http://checkstyle.sf.net/config_misc.html#Translation --> | |
43 | <module name="Translation"/> | |
44 | ||
45 | <!-- Checks for Size Violations. --> | |
46 | <!-- See http://checkstyle.sf.net/config_sizes.html --> | |
47 | <module name="FileLength"/> | |
48 | <module name="LineLength"> | |
49 | <property name="max" value="120"/> | |
50 | </module> | |
51 | ||
52 | <!-- Checks for whitespace --> | |
53 | <!-- See http://checkstyle.sf.net/config_whitespace.html --> | |
54 | <module name="FileTabCharacter"/> | |
55 | ||
56 | <!-- Miscellaneous other checks. --> | |
57 | <!-- See http://checkstyle.sf.net/config_misc.html --> | |
58 | <module name="RegexpSingleline"> | |
59 | <property name="format" value="\s+$"/> | |
60 | <property name="minimum" value="0"/> | |
61 | <property name="maximum" value="0"/> | |
62 | <property name="message" value="Line has trailing spaces."/> | |
63 | </module> | |
64 | ||
65 | <!-- Checks for Headers --> | |
66 | <!-- See http://checkstyle.sf.net/config_header.html --> | |
67 | <!-- <module name="Header"> --> | |
68 | <!-- <property name="headerFile" value="${checkstyle.header.file}"/> --> | |
69 | <!-- <property name="fileExtensions" value="java"/> --> | |
70 | <!-- </module> --> | |
71 | ||
72 | ||
73 | <module name="TreeWalker"> | |
74 | ||
75 | <!-- Make annotations available for filtering via SuppressWarningsFilter --> | |
76 | <module name="SuppressWarningsHolder"/> | |
77 | ||
78 | <!-- Checks for Javadoc comments. --> | |
79 | <!-- See http://checkstyle.sf.net/config_javadoc.html --> | |
80 | <module name="JavadocMethod"/> | |
81 | <module name="JavadocType"/> | |
82 | <module name="JavadocVariable"/> | |
83 | <module name="JavadocStyle"/> | |
84 | ||
85 | <!-- Checks for Naming Conventions. --> | |
86 | <!-- See http://checkstyle.sf.net/config_naming.html --> | |
87 | <module name="ConstantName"> | |
88 | <property name="format" value="^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*|logger$"/> | |
89 | </module> | |
90 | <module name="LocalFinalVariableName"/> | |
91 | <module name="LocalVariableName"/> | |
92 | <module name="MemberName"/> | |
93 | <module name="MethodName"/> | |
94 | <module name="PackageName"/> | |
95 | <module name="ParameterName"/> | |
96 | <module name="StaticVariableName"/> | |
97 | <module name="TypeName"/> | |
98 | ||
99 | <!-- Checks for imports --> | |
100 | <!-- See http://checkstyle.sf.net/config_import.html --> | |
101 | <module name="AvoidStarImport"/> | |
102 | <module name="IllegalImport"/> <!-- defaults to sun.* packages --> | |
103 | <module name="RedundantImport"/> | |
104 | <module name="UnusedImports"/> | |
105 | ||
106 | <!-- Checks for Size Violations. --> | |
107 | <!-- See http://checkstyle.sf.net/config_sizes.html --> | |
108 | <module name="MethodLength"/> | |
109 | <module name="ParameterNumber"> | |
110 | <!--<property name="max" value="7"/>--> | |
111 | <property name="max" value="10"/> | |
112 | </module> | |
113 | ||
114 | <!-- Checks for whitespace --> | |
115 | <!-- See http://checkstyle.sf.net/config_whitespace.html --> | |
116 | <module name="EmptyForIteratorPad"/> | |
117 | <module name="GenericWhitespace"/> | |
118 | <module name="MethodParamPad"/> | |
119 | <module name="NoWhitespaceAfter"/> | |
120 | <module name="NoWhitespaceBefore"/> | |
121 | <module name="OperatorWrap"/> | |
122 | <module name="ParenPad"/> | |
123 | <module name="TypecastParenPad"/> | |
124 | <module name="WhitespaceAfter"> | |
125 | <property name="tokens" value="COMMA, SEMI"/> | |
126 | </module> | |
127 | <module name="WhitespaceAround"/> | |
128 | ||
129 | <!-- Modifier Checks --> | |
130 | <!-- See http://checkstyle.sf.net/config_modifiers.html --> | |
131 | <module name="ModifierOrder"/> | |
132 | <module name="RedundantModifier"/> | |
133 | ||
134 | <!-- Checks for blocks. You know, those {}'s --> | |
135 | <!-- See http://checkstyle.sf.net/config_blocks.html --> | |
136 | <module name="AvoidNestedBlocks"/> | |
137 | <module name="EmptyBlock"/> | |
138 | <module name="LeftCurly"/> | |
139 | <module name="NeedBraces"/> | |
140 | <module name="RightCurly"/> | |
141 | ||
142 | <!-- Checks for common coding problems --> | |
143 | <!-- See http://checkstyle.sf.net/config_coding.html --> | |
144 | <module name="AvoidInlineConditionals"/> | |
145 | <module name="EmptyStatement"/> | |
146 | <module name="EqualsHashCode"/> | |
147 | <module name="HiddenField"> | |
148 | <property name="ignoreSetter" value="true"/> | |
149 | <property name="ignoreConstructorParameter" value="true"/> | |
150 | <property name="setterCanReturnItsClass" value="true"/> | |
151 | </module> | |
152 | <module name="IllegalInstantiation"/> | |
153 | <module name="InnerAssignment"/> | |
154 | <module name="MagicNumber"/> | |
155 | <module name="MissingSwitchDefault"/> | |
156 | <module name="SimplifyBooleanExpression"/> | |
157 | <module name="SimplifyBooleanReturn"/> | |
158 | ||
159 | <!-- Checks for class design --> | |
160 | <!-- See http://checkstyle.sf.net/config_design.html --> | |
161 | <!--<module name="DesignForExtension"/>--> | |
162 | <module name="FinalClass"/> | |
163 | <module name="HideUtilityClassConstructor"/> | |
164 | <module name="InterfaceIsType"/> | |
165 | <module name="VisibilityModifier"/> | |
166 | ||
167 | <!-- Miscellaneous other checks. --> | |
168 | <!-- See http://checkstyle.sf.net/config_misc.html --> | |
169 | <module name="ArrayTypeStyle"/> | |
170 | <module name="FinalParameters"/> | |
171 | <module name="TodoComment"/> | |
172 | <module name="UpperEll"/> | |
173 | ||
174 | </module> | |
175 | ||
176 | </module>⏎ |
0 | ||
1 | GNU LESSER GENERAL PUBLIC LICENSE | |
2 | Version 2.1, February 1999 | |
3 | ||
4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. | |
5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
6 | Everyone is permitted to copy and distribute verbatim copies | |
7 | of this license document, but changing it is not allowed. | |
8 | ||
9 | [This is the first released version of the Lesser GPL. It also counts | |
10 | as the successor of the GNU Library Public License, version 2, hence | |
11 | the version number 2.1.] | |
12 | ||
13 | Preamble | |
14 | ||
15 | The licenses for most software are designed to take away your | |
16 | freedom to share and change it. By contrast, the GNU General Public | |
17 | Licenses are intended to guarantee your freedom to share and change | |
18 | free software--to make sure the software is free for all its users. | |
19 | ||
20 | This license, the Lesser General Public License, applies to some | |
21 | specially designated software packages--typically libraries--of the | |
22 | Free Software Foundation and other authors who decide to use it. You | |
23 | can use it too, but we suggest you first think carefully about whether | |
24 | this license or the ordinary General Public License is the better | |
25 | strategy to use in any particular case, based on the explanations | |
26 | below. | |
27 | ||
28 | When we speak of free software, we are referring to freedom of use, | |
29 | not price. Our General Public Licenses are designed to make sure that | |
30 | you have the freedom to distribute copies of free software (and charge | |
31 | for this service if you wish); that you receive source code or can get | |
32 | it if you want it; that you can change the software and use pieces of | |
33 | it in new free programs; and that you are informed that you can do | |
34 | these things. | |
35 | ||
36 | To protect your rights, we need to make restrictions that forbid | |
37 | distributors to deny you these rights or to ask you to surrender these | |
38 | rights. These restrictions translate to certain responsibilities for | |
39 | you if you distribute copies of the library or if you modify it. | |
40 | ||
41 | For example, if you distribute copies of the library, whether gratis | |
42 | or for a fee, you must give the recipients all the rights that we gave | |
43 | you. You must make sure that they, too, receive or can get the source | |
44 | code. If you link other code with the library, you must provide | |
45 | complete object files to the recipients, so that they can relink them | |
46 | with the library after making changes to the library and recompiling | |
47 | it. And you must show them these terms so they know their rights. | |
48 | ||
49 | We protect your rights with a two-step method: (1) we copyright the | |
50 | library, and (2) we offer you this license, which gives you legal | |
51 | permission to copy, distribute and/or modify the library. | |
52 | ||
53 | To protect each distributor, we want to make it very clear that | |
54 | there is no warranty for the free library. Also, if the library is | |
55 | modified by someone else and passed on, the recipients should know | |
56 | that what they have is not the original version, so that the original | |
57 | author's reputation will not be affected by problems that might be | |
58 | introduced by others. | |
59 | ||
60 | Finally, software patents pose a constant threat to the existence of | |
61 | any free program. We wish to make sure that a company cannot | |
62 | effectively restrict the users of a free program by obtaining a | |
63 | restrictive license from a patent holder. Therefore, we insist that | |
64 | any patent license obtained for a version of the library must be | |
65 | consistent with the full freedom of use specified in this license. | |
66 | ||
67 | Most GNU software, including some libraries, is covered by the | |
68 | ordinary GNU General Public License. This license, the GNU Lesser | |
69 | General Public License, applies to certain designated libraries, and | |
70 | is quite different from the ordinary General Public License. We use | |
71 | this license for certain libraries in order to permit linking those | |
72 | libraries into non-free programs. | |
73 | ||
74 | When a program is linked with a library, whether statically or using | |
75 | a shared library, the combination of the two is legally speaking a | |
76 | combined work, a derivative of the original library. The ordinary | |
77 | General Public License therefore permits such linking only if the | |
78 | entire combination fits its criteria of freedom. The Lesser General | |
79 | Public License permits more lax criteria for linking other code with | |
80 | the library. | |
81 | ||
82 | We call this license the "Lesser" General Public License because it | |
83 | does Less to protect the user's freedom than the ordinary General | |
84 | Public License. It also provides other free software developers Less | |
85 | of an advantage over competing non-free programs. These disadvantages | |
86 | are the reason we use the ordinary General Public License for many | |
87 | libraries. However, the Lesser license provides advantages in certain | |
88 | special circumstances. | |
89 | ||
90 | For example, on rare occasions, there may be a special need to | |
91 | encourage the widest possible use of a certain library, so that it | |
92 | becomes a de-facto standard. To achieve this, non-free programs must | |
93 | be allowed to use the library. A more frequent case is that a free | |
94 | library does the same job as widely used non-free libraries. In this | |
95 | case, there is little to gain by limiting the free library to free | |
96 | software only, so we use the Lesser General Public License. | |
97 | ||
98 | In other cases, permission to use a particular library in non-free | |
99 | programs enables a greater number of people to use a large body of | |
100 | free software. For example, permission to use the GNU C Library in | |
101 | non-free programs enables many more people to use the whole GNU | |
102 | operating system, as well as its variant, the GNU/Linux operating | |
103 | system. | |
104 | ||
105 | Although the Lesser General Public License is Less protective of the | |
106 | users' freedom, it does ensure that the user of a program that is | |
107 | linked with the Library has the freedom and the wherewithal to run | |
108 | that program using a modified version of the Library. | |
109 | ||
110 | The precise terms and conditions for copying, distribution and | |
111 | modification follow. Pay close attention to the difference between a | |
112 | "work based on the library" and a "work that uses the library". The | |
113 | former contains code derived from the library, whereas the latter must | |
114 | be combined with the library in order to run. | |
115 | ||
116 | GNU LESSER GENERAL PUBLIC LICENSE | |
117 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
118 | ||
119 | 0. This License Agreement applies to any software library or other | |
120 | program which contains a notice placed by the copyright holder or | |
121 | other authorized party saying it may be distributed under the terms of | |
122 | this Lesser General Public License (also called "this License"). | |
123 | Each licensee is addressed as "you". | |
124 | ||
125 | A "library" means a collection of software functions and/or data | |
126 | prepared so as to be conveniently linked with application programs | |
127 | (which use some of those functions and data) to form executables. | |
128 | ||
129 | The "Library", below, refers to any such software library or work | |
130 | which has been distributed under these terms. A "work based on the | |
131 | Library" means either the Library or any derivative work under | |
132 | copyright law: that is to say, a work containing the Library or a | |
133 | portion of it, either verbatim or with modifications and/or translated | |
134 | straightforwardly into another language. (Hereinafter, translation is | |
135 | included without limitation in the term "modification".) | |
136 | ||
137 | "Source code" for a work means the preferred form of the work for | |
138 | making modifications to it. For a library, complete source code means | |
139 | all the source code for all modules it contains, plus any associated | |
140 | interface definition files, plus the scripts used to control | |
141 | compilation and installation of the library. | |
142 | ||
143 | Activities other than copying, distribution and modification are not | |
144 | covered by this License; they are outside its scope. The act of | |
145 | running a program using the Library is not restricted, and output from | |
146 | such a program is covered only if its contents constitute a work based | |
147 | on the Library (independent of the use of the Library in a tool for | |
148 | writing it). Whether that is true depends on what the Library does | |
149 | and what the program that uses the Library does. | |
150 | ||
151 | 1. You may copy and distribute verbatim copies of the Library's | |
152 | complete source code as you receive it, in any medium, provided that | |
153 | you conspicuously and appropriately publish on each copy an | |
154 | appropriate copyright notice and disclaimer of warranty; keep intact | |
155 | all the notices that refer to this License and to the absence of any | |
156 | warranty; and distribute a copy of this License along with the | |
157 | Library. | |
158 | ||
159 | You may charge a fee for the physical act of transferring a copy, | |
160 | and you may at your option offer warranty protection in exchange for a | |
161 | fee. | |
162 | ||
163 | 2. You may modify your copy or copies of the Library or any portion | |
164 | of it, thus forming a work based on the Library, and copy and | |
165 | distribute such modifications or work under the terms of Section 1 | |
166 | above, provided that you also meet all of these conditions: | |
167 | ||
168 | a) The modified work must itself be a software library. | |
169 | ||
170 | b) You must cause the files modified to carry prominent notices | |
171 | stating that you changed the files and the date of any change. | |
172 | ||
173 | c) You must cause the whole of the work to be licensed at no | |
174 | charge to all third parties under the terms of this License. | |
175 | ||
176 | d) If a facility in the modified Library refers to a function or a | |
177 | table of data to be supplied by an application program that uses | |
178 | the facility, other than as an argument passed when the facility | |
179 | is invoked, then you must make a good faith effort to ensure that, | |
180 | in the event an application does not supply such function or | |
181 | table, the facility still operates, and performs whatever part of | |
182 | its purpose remains meaningful. | |
183 | ||
184 | (For example, a function in a library to compute square roots has | |
185 | a purpose that is entirely well-defined independent of the | |
186 | application. Therefore, Subsection 2d requires that any | |
187 | application-supplied function or table used by this function must | |
188 | be optional: if the application does not supply it, the square | |
189 | root function must still compute square roots.) | |
190 | ||
191 | These requirements apply to the modified work as a whole. If | |
192 | identifiable sections of that work are not derived from the Library, | |
193 | and can be reasonably considered independent and separate works in | |
194 | themselves, then this License, and its terms, do not apply to those | |
195 | sections when you distribute them as separate works. But when you | |
196 | distribute the same sections as part of a whole which is a work based | |
197 | on the Library, the distribution of the whole must be on the terms of | |
198 | this License, whose permissions for other licensees extend to the | |
199 | entire whole, and thus to each and every part regardless of who wrote | |
200 | it. | |
201 | ||
202 | Thus, it is not the intent of this section to claim rights or contest | |
203 | your rights to work written entirely by you; rather, the intent is to | |
204 | exercise the right to control the distribution of derivative or | |
205 | collective works based on the Library. | |
206 | ||
207 | In addition, mere aggregation of another work not based on the Library | |
208 | with the Library (or with a work based on the Library) on a volume of | |
209 | a storage or distribution medium does not bring the other work under | |
210 | the scope of this License. | |
211 | ||
212 | 3. You may opt to apply the terms of the ordinary GNU General Public | |
213 | License instead of this License to a given copy of the Library. To do | |
214 | this, you must alter all the notices that refer to this License, so | |
215 | that they refer to the ordinary GNU General Public License, version 2, | |
216 | instead of to this License. (If a newer version than version 2 of the | |
217 | ordinary GNU General Public License has appeared, then you can specify | |
218 | that version instead if you wish.) Do not make any other change in | |
219 | these notices. | |
220 | ||
221 | Once this change is made in a given copy, it is irreversible for | |
222 | that copy, so the ordinary GNU General Public License applies to all | |
223 | subsequent copies and derivative works made from that copy. | |
224 | ||
225 | This option is useful when you wish to copy part of the code of | |
226 | the Library into a program that is not a library. | |
227 | ||
228 | 4. You may copy and distribute the Library (or a portion or | |
229 | derivative of it, under Section 2) in object code or executable form | |
230 | under the terms of Sections 1 and 2 above provided that you accompany | |
231 | it with the complete corresponding machine-readable source code, which | |
232 | must be distributed under the terms of Sections 1 and 2 above on a | |
233 | medium customarily used for software interchange. | |
234 | ||
235 | If distribution of object code is made by offering access to copy | |
236 | from a designated place, then offering equivalent access to copy the | |
237 | source code from the same place satisfies the requirement to | |
238 | distribute the source code, even though third parties are not | |
239 | compelled to copy the source along with the object code. | |
240 | ||
241 | 5. A program that contains no derivative of any portion of the | |
242 | Library, but is designed to work with the Library by being compiled or | |
243 | linked with it, is called a "work that uses the Library". Such a | |
244 | work, in isolation, is not a derivative work of the Library, and | |
245 | therefore falls outside the scope of this License. | |
246 | ||
247 | However, linking a "work that uses the Library" with the Library | |
248 | creates an executable that is a derivative of the Library (because it | |
249 | contains portions of the Library), rather than a "work that uses the | |
250 | library". The executable is therefore covered by this License. | |
251 | Section 6 states terms for distribution of such executables. | |
252 | ||
253 | When a "work that uses the Library" uses material from a header file | |
254 | that is part of the Library, the object code for the work may be a | |
255 | derivative work of the Library even though the source code is not. | |
256 | Whether this is true is especially significant if the work can be | |
257 | linked without the Library, or if the work is itself a library. The | |
258 | threshold for this to be true is not precisely defined by law. | |
259 | ||
260 | If such an object file uses only numerical parameters, data | |
261 | structure layouts and accessors, and small macros and small inline | |
262 | functions (ten lines or less in length), then the use of the object | |
263 | file is unrestricted, regardless of whether it is legally a derivative | |
264 | work. (Executables containing this object code plus portions of the | |
265 | Library will still fall under Section 6.) | |
266 | ||
267 | Otherwise, if the work is a derivative of the Library, you may | |
268 | distribute the object code for the work under the terms of Section 6. | |
269 | Any executables containing that work also fall under Section 6, | |
270 | whether or not they are linked directly with the Library itself. | |
271 | ||
272 | 6. As an exception to the Sections above, you may also combine or | |
273 | link a "work that uses the Library" with the Library to produce a | |
274 | work containing portions of the Library, and distribute that work | |
275 | under terms of your choice, provided that the terms permit | |
276 | modification of the work for the customer's own use and reverse | |
277 | engineering for debugging such modifications. | |
278 | ||
279 | You must give prominent notice with each copy of the work that the | |
280 | Library is used in it and that the Library and its use are covered by | |
281 | this License. You must supply a copy of this License. If the work | |
282 | during execution displays copyright notices, you must include the | |
283 | copyright notice for the Library among them, as well as a reference | |
284 | directing the user to the copy of this License. Also, you must do one | |
285 | of these things: | |
286 | ||
287 | a) Accompany the work with the complete corresponding | |
288 | machine-readable source code for the Library including whatever | |
289 | changes were used in the work (which must be distributed under | |
290 | Sections 1 and 2 above); and, if the work is an executable linked | |
291 | with the Library, with the complete machine-readable "work that | |
292 | uses the Library", as object code and/or source code, so that the | |
293 | user can modify the Library and then relink to produce a modified | |
294 | executable containing the modified Library. (It is understood | |
295 | that the user who changes the contents of definitions files in the | |
296 | Library will not necessarily be able to recompile the application | |
297 | to use the modified definitions.) | |
298 | ||
299 | b) Use a suitable shared library mechanism for linking with the | |
300 | Library. A suitable mechanism is one that (1) uses at run time a | |
301 | copy of the library already present on the user's computer system, | |
302 | rather than copying library functions into the executable, and (2) | |
303 | will operate properly with a modified version of the library, if | |
304 | the user installs one, as long as the modified version is | |
305 | interface-compatible with the version that the work was made with. | |
306 | ||
307 | c) Accompany the work with a written offer, valid for at least | |
308 | three years, to give the same user the materials specified in | |
309 | Subsection 6a, above, for a charge no more than the cost of | |
310 | performing this distribution. | |
311 | ||
312 | d) If distribution of the work is made by offering access to copy | |
313 | from a designated place, offer equivalent access to copy the above | |
314 | specified materials from the same place. | |
315 | ||
316 | e) Verify that the user has already received a copy of these | |
317 | materials or that you have already sent this user a copy. | |
318 | ||
319 | For an executable, the required form of the "work that uses the | |
320 | Library" must include any data and utility programs needed for | |
321 | reproducing the executable from it. However, as a special exception, | |
322 | the materials to be distributed need not include anything that is | |
323 | normally distributed (in either source or binary form) with the major | |
324 | components (compiler, kernel, and so on) of the operating system on | |
325 | which the executable runs, unless that component itself accompanies | |
326 | the executable. | |
327 | ||
328 | It may happen that this requirement contradicts the license | |
329 | restrictions of other proprietary libraries that do not normally | |
330 | accompany the operating system. Such a contradiction means you cannot | |
331 | use both them and the Library together in an executable that you | |
332 | distribute. | |
333 | ||
334 | 7. You may place library facilities that are a work based on the | |
335 | Library side-by-side in a single library together with other library | |
336 | facilities not covered by this License, and distribute such a combined | |
337 | library, provided that the separate distribution of the work based on | |
338 | the Library and of the other library facilities is otherwise | |
339 | permitted, and provided that you do these two things: | |
340 | ||
341 | a) Accompany the combined library with a copy of the same work | |
342 | based on the Library, uncombined with any other library | |
343 | facilities. This must be distributed under the terms of the | |
344 | Sections above. | |
345 | ||
346 | b) Give prominent notice with the combined library of the fact | |
347 | that part of it is a work based on the Library, and explaining | |
348 | where to find the accompanying uncombined form of the same work. | |
349 | ||
350 | 8. You may not copy, modify, sublicense, link with, or distribute | |
351 | the Library except as expressly provided under this License. Any | |
352 | attempt otherwise to copy, modify, sublicense, link with, or | |
353 | distribute the Library is void, and will automatically terminate your | |
354 | rights under this License. However, parties who have received copies, | |
355 | or rights, from you under this License will not have their licenses | |
356 | terminated so long as such parties remain in full compliance. | |
357 | ||
358 | 9. You are not required to accept this License, since you have not | |
359 | signed it. However, nothing else grants you permission to modify or | |
360 | distribute the Library or its derivative works. These actions are | |
361 | prohibited by law if you do not accept this License. Therefore, by | |
362 | modifying or distributing the Library (or any work based on the | |
363 | Library), you indicate your acceptance of this License to do so, and | |
364 | all its terms and conditions for copying, distributing or modifying | |
365 | the Library or works based on it. | |
366 | ||
367 | 10. Each time you redistribute the Library (or any work based on the | |
368 | Library), the recipient automatically receives a license from the | |
369 | original licensor to copy, distribute, link with or modify the Library | |
370 | subject to these terms and conditions. You may not impose any further | |
371 | restrictions on the recipients' exercise of the rights granted herein. | |
372 | You are not responsible for enforcing compliance by third parties with | |
373 | this License. | |
374 | ||
375 | 11. If, as a consequence of a court judgment or allegation of patent | |
376 | infringement or for any other reason (not limited to patent issues), | |
377 | conditions are imposed on you (whether by court order, agreement or | |
378 | otherwise) that contradict the conditions of this License, they do not | |
379 | excuse you from the conditions of this License. If you cannot | |
380 | distribute so as to satisfy simultaneously your obligations under this | |
381 | License and any other pertinent obligations, then as a consequence you | |
382 | may not distribute the Library at all. For example, if a patent | |
383 | license would not permit royalty-free redistribution of the Library by | |
384 | all those who receive copies directly or indirectly through you, then | |
385 | the only way you could satisfy both it and this License would be to | |
386 | refrain entirely from distribution of the Library. | |
387 | ||
388 | If any portion of this section is held invalid or unenforceable under | |
389 | any particular circumstance, the balance of the section is intended to | |
390 | apply, and the section as a whole is intended to apply in other | |
391 | circumstances. | |
392 | ||
393 | It is not the purpose of this section to induce you to infringe any | |
394 | patents or other property right claims or to contest validity of any | |
395 | such claims; this section has the sole purpose of protecting the | |
396 | integrity of the free software distribution system which is | |
397 | implemented by public license practices. Many people have made | |
398 | generous contributions to the wide range of software distributed | |
399 | through that system in reliance on consistent application of that | |
400 | system; it is up to the author/donor to decide if he or she is willing | |
401 | to distribute software through any other system and a licensee cannot | |
402 | impose that choice. | |
403 | ||
404 | This section is intended to make thoroughly clear what is believed to | |
405 | be a consequence of the rest of this License. | |
406 | ||
407 | 12. If the distribution and/or use of the Library is restricted in | |
408 | certain countries either by patents or by copyrighted interfaces, the | |
409 | original copyright holder who places the Library under this License | |
410 | may add an explicit geographical distribution limitation excluding those | |
411 | countries, so that distribution is permitted only in or among | |
412 | countries not thus excluded. In such case, this License incorporates | |
413 | the limitation as if written in the body of this License. | |
414 | ||
415 | 13. The Free Software Foundation may publish revised and/or new | |
416 | versions of the Lesser General Public License from time to time. | |
417 | Such new versions will be similar in spirit to the present version, | |
418 | but may differ in detail to address new problems or concerns. | |
419 | ||
420 | Each version is given a distinguishing version number. If the Library | |
421 | specifies a version number of this License which applies to it and | |
422 | "any later version", you have the option of following the terms and | |
423 | conditions either of that version or of any later version published by | |
424 | the Free Software Foundation. If the Library does not specify a | |
425 | license version number, you may choose any version ever published by | |
426 | the Free Software Foundation. | |
427 | ||
428 | 14. If you wish to incorporate parts of the Library into other free | |
429 | programs whose distribution conditions are incompatible with these, | |
430 | write to the author to ask for permission. For software which is | |
431 | copyrighted by the Free Software Foundation, write to the Free | |
432 | Software Foundation; we sometimes make exceptions for this. Our | |
433 | decision will be guided by the two goals of preserving the free status | |
434 | of all derivatives of our free software and of promoting the sharing | |
435 | and reuse of software generally. | |
436 | ||
437 | NO WARRANTY | |
438 | ||
439 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO | |
440 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. | |
441 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR | |
442 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY | |
443 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE | |
444 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
445 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE | |
446 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME | |
447 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | |
448 | ||
449 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN | |
450 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY | |
451 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU | |
452 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR | |
453 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE | |
454 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING | |
455 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A | |
456 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF | |
457 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |
458 | DAMAGES. | |
459 | ||
460 | END OF TERMS AND CONDITIONS | |
461 | ||
462 | How to Apply These Terms to Your New Libraries | |
463 | ||
464 | If you develop a new library, and you want it to be of the greatest | |
465 | possible use to the public, we recommend making it free software that | |
466 | everyone can redistribute and change. You can do so by permitting | |
467 | redistribution under these terms (or, alternatively, under the terms | |
468 | of the ordinary General Public License). | |
469 | ||
470 | To apply these terms, attach the following notices to the library. | |
471 | It is safest to attach them to the start of each source file to most | |
472 | effectively convey the exclusion of warranty; and each file should | |
473 | have at least the "copyright" line and a pointer to where the full | |
474 | notice is found. | |
475 | ||
476 | ||
477 | <one line to give the library's name and a brief idea of what it does.> | |
478 | Copyright (C) <year> <name of author> | |
479 | ||
480 | This library is free software; you can redistribute it and/or | |
481 | modify it under the terms of the GNU Lesser General Public | |
482 | License as published by the Free Software Foundation; either | |
483 | version 2.1 of the License, or (at your option) any later version. | |
484 | ||
485 | This library is distributed in the hope that it will be useful, | |
486 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
487 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
488 | Lesser General Public License for more details. | |
489 | ||
490 | You should have received a copy of the GNU Lesser General Public | |
491 | License along with this library; if not, write to the Free Software | |
492 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
493 | ||
494 | Also add information on how to contact you by electronic and paper mail. | |
495 | ||
496 | You should also get your employer (if you work as a programmer) or | |
497 | your school, if any, to sign a "copyright disclaimer" for the library, | |
498 | if necessary. Here is a sample; alter the names: | |
499 | ||
500 | Yoyodyne, Inc., hereby disclaims all copyright interest in the | |
501 | library `Frob' (a library for tweaking knobs) written by James | |
502 | Random Hacker. | |
503 | ||
504 | <signature of Ty Coon>, 1 April 1990 | |
505 | Ty Coon, President of Vice | |
506 | ||
507 | That's all there is to it! | |
508 | ||
509 |
0 | ||
1 | *** PostGIS JDBC Driver extension README / FAQ *** | |
2 | ||
3 | (C) 2005 Markus Schaber <markus.schaber@logix-tt.com> | |
4 | ||
5 | ||
6 | * What is it all about? * | |
7 | ||
8 | JDBC is an database driver specification for Java. Like ODBC in the C | |
9 | world, JDBC allows java applications to transparently use different | |
10 | JDBC compliant databases without any source code changes. PostgreSQL, | |
11 | the database PostGIS is written for, comes with a driver that | |
12 | follows this specification. For downloads and more info, see: | |
13 | http://jdbc.postgresql.org/download.html | |
14 | ||
15 | The purpose of the JDBC Driver extension is to give the PostgreSQL | |
16 | JDBC driver some understanding of the PostGIS data types (Geometry, | |
17 | Box3D, Box2D). Without this, the Application can only get byte arrays | |
18 | or strings (binary and text representation, rsp.) and has to parse it | |
19 | on its own. When registering this extension, the Application can | |
20 | simply call getObject(column) on the result of the query, and get a | |
21 | real java object that is modeled after the OpenGIS spec. It also can | |
22 | create or modify this objects itsself and then pass them into the | |
23 | database via the PreparedStatement.setObject() method. | |
24 | ||
25 | Currently, the code is tested with PostGIS 0.8.1, 0.9.1. 0.9.2 and | |
26 | 1.0.0. It supports both the new hex-encoded EWKB canonical text | |
27 | representation used by PostGIS 1.0.0 lwgeom code, and the old, less | |
28 | efficient WKT like representation used by previous releases when | |
29 | reading data from the server. When sending data to the server, it | |
30 | currently always uses the latter form, which is compatible to all | |
31 | PostGIS versions. | |
32 | ||
33 | ||
34 | * Do I need it? * | |
35 | ||
36 | If you happen to write GIS applications, you can propably benefit. | |
37 | ||
38 | In case your applications are PostGIS specific, you can fully exploit | |
39 | the functionality, see "How to I use it" below for instructions and | |
40 | the src/examples directory for some code examples. | |
41 | ||
42 | If you rather prefer to stay OpenGIS compliant, then you cannot use | |
43 | the full driver embedding, as this is PostGIS specific functionality. | |
44 | But you can still use the geometry classes as a lightweight java | |
45 | geometry model if you do not want to use a full-blown GIS | |
46 | implementation like jts. Simply use the asText() and | |
47 | GeometryFromText() OpenGIS SQL functions against whichever OpenGIS | |
48 | compliant server you want, and use the WKT parsing constructors or | |
49 | PGgeometry.geomFromString() as well as Geometry.toString() to convert | |
50 | between WKT strings and geometry objects. | |
51 | ||
52 | ||
53 | * Is it free? * | |
54 | ||
55 | Yes. The actual Driver extension code is licensed under the GNU LGPL, | |
56 | this allows everyone to include the code in his projects. You do not | |
57 | have to pay any license fees, and you can keep your own application | |
58 | code proprietary, but you have to make the PostGIS source code available | |
59 | to any receivers, including any modifications you apply to it. For | |
60 | details, please see the license file COPYING_LGPL. | |
61 | ||
62 | The Build files and examples are licensed under GNU GPL, just like the | |
63 | rest of PostGIS is. This is not LGPL as applications usually do not | |
64 | link against those. | |
65 | ||
66 | ||
67 | * How do I build it? * | |
68 | ||
69 | There are older make files with which you can try to build, but maven is recommended, | |
70 | as it handles dependencies on a better and cleaner way. | |
71 | ||
72 | You have to install maven on your computer to build it. To install maven you can try | |
73 | to search on your software repositories or read the documentation: | |
74 | http://maven.apache.org/download.html | |
75 | ||
76 | To compile your postgis driver, go to the jdbc folder and execute the console | |
77 | command "mvn package". This should create a postgis jar on the target folder | |
78 | inside the jdbc folder. | |
79 | ||
80 | Note that your postgis driver version does not constrain the PostgreSQL | |
81 | server version. As the JDBC drivers are downwards compatible against older | |
82 | servers, and PostgreSQL servers typically accept older clients, you can | |
83 | easily use e. G. a pgjdbc 8.0 against a PostgreSQL 7.3 server. To benefit | |
84 | from optimizations and bugfixes, it is generally suggested to use the | |
85 | newest stable pgjdbc build that is documented to work against your | |
86 | server release. | |
87 | ||
88 | * It is called jdbc2 - does it work with jdbc3, too? * | |
89 | ||
90 | To make it short: The naming does not refer to SUN jdbc standard releases | |
91 | jdbc-1, jdbc-2 or jdbc-3. | |
92 | ||
93 | The current naming is somehow unfortunate. The directory simply is named | |
94 | jdbc2 because it is the successor of Paul Ramsey's original jdbc directory, | |
95 | which used to exist parallel in the CVS repository. As CVS does its best | |
96 | to hinder useful version tracking across file renames, the name was kept | |
97 | even after removal of the original jdbc subproject. | |
98 | ||
99 | Please note that the PostgreSQL JDBC driver itsself is released in | |
100 | several flavours for different JDBC relases and sun JDK releases, but | |
101 | currently, the same postgis.jar should work with all of them. If not, | |
102 | you clearly found a bug, and we kindly ask you to report it. | |
103 | ||
104 | If you run into troubles, make shure that you use the newest pgjdbc build. | |
105 | Especially pre releases are known to contain bugs (that's why they are pre | |
106 | releases), and e. G. 8.0 build 309 contained some problems that are fixed | |
107 | in 8.0 build 313. | |
108 | ||
109 | ||
110 | * How do I use it? * | |
111 | ||
112 | To use the PostGIS types, you need the postgis.jar and the pgjdbc | |
113 | driver in your classpath. | |
114 | ||
115 | The PostGIS extension must be registered within the JDBC driver. | |
116 | There are three ways to do this: | |
117 | ||
118 | - If you use pgjdbc 8.0, the org/postgresql/driverconfig.properties | |
119 | file contained in the postgis.jar autoregisters the PostGIS | |
120 | extension for the PostGIS data types (geometry, box2d, box3d) | |
121 | within the pgjdbc driver. | |
122 | ||
123 | - You can use the org.postgis.DriverWrapper as replacement for the | |
124 | jdbc driver. This class wraps the PostGreSQL Driver to | |
125 | transparently add the PostGIS Object Classes. This method currently | |
126 | works both with J2EE DataSources, and with the older DriverManager | |
127 | framework. I's a thin wrapper around org.postgresql.Driver that | |
128 | simply registers the extension on every new connection created. | |
129 | ||
130 | To use it, you replace the "jdbc:postgresql:" with a | |
131 | "jdbc:postgresql_postGIS" in the jdbc URL, and make your | |
132 | environment aware of the new Driver class. | |
133 | ||
134 | DriverManager users simply register org/postgis/DriverWrapper | |
135 | instead of (or in addition to) org.postgresql.Driver, see | |
136 | examples/TestBoxes.connect() for an working code. | |
137 | ||
138 | DataSource users similarly have to configure their datasource to | |
139 | use the different class. The following works for jboss, put it in | |
140 | your-ds.xml: <driver-class>org.postgis.DriverWrapper</driver-class> | |
141 | ||
142 | - Of course, you can also manually register the Datatypes on your | |
143 | pgjdbc connection. You have to cast your connection to PGConnection | |
144 | and then call: | |
145 | ||
146 | pgconn.addDataType("geometry", "org.postgis.PGgeometry"); | |
147 | pgconn.addDataType("box3d", "org.postgis.PGbox3d"); | |
148 | pgconn.addDataType("box2d", "org.postgis.PGbox2d"); | |
149 | ||
150 | You may need to dig through some wrappers when running in an | |
151 | appserver. E. G. for JBoss, The datasource actually gives you a | |
152 | instance of org.jboss.resource.adapter.jdbc.WrappedConnection and | |
153 | have to call getUnderlyingConnection() on it to get the | |
154 | PGConnection instance.) | |
155 | ||
156 | Also note that the above addDataType() methods known from earlier | |
157 | pgjdbc versions are deprecated in pgjdbc 8.0 (but still work), see | |
158 | the commented code variants in the DriverWrapper.addGisTypes() | |
159 | method for an alternative. | |
160 | ||
161 | Note: Even using pgjdbc 8.0, you may still want to use the second or | |
162 | third approach if you have several pgjdbc extensions that | |
163 | autoregister for the same PostGIS types, as the driver cannot guess | |
164 | which extension it should actually use on which connection. The | |
165 | current pgjdbc implementation simply parses all | |
166 | org/postgresql/driverconfig.properties the classloader can find in his | |
167 | classpath, using the first definition found for each type. | |
168 | ||
169 | ||
170 | * How to I run the tests? Are they allowed to fail? * | |
171 | ||
172 | There are two types of tests provided, offline and online. Offline | |
173 | tests can run without a PostGIS server, the online tests need a | |
174 | PostGIS server to connect to. | |
175 | ||
176 | - Offline Tests | |
177 | ||
178 | The easiest way to run the offline tests is "make offlinetests". | |
179 | ||
180 | The offline tests should always complete without any failure. If | |
181 | you happen to get a failure here, it is a bug in the PostGIS code | |
182 | (or, very unlikely, in the JDK/JRE or Hardware you use). Please | |
183 | contact the PostGIS developer list in this case. | |
184 | ||
185 | - Online tests | |
186 | ||
187 | The online tests can be ran with "make onlinetests", but they need | |
188 | a specially prepared database to connect against, and the pgjdbc | |
189 | driver available in your classpath. The Makefile provides defaults | |
190 | for PGHOST, PGPOR, PGDATABASE, PGUSER and PGPASS, you can override | |
191 | them for your needs. For the jtest, the user needs to create and | |
192 | drop table privileges, the two other tests do not use any table. | |
193 | Make shure you have the PostGIS installed in the database. | |
194 | ||
195 | None of the online tests should report any failure. However, some of the | |
196 | tests are skipped against PostGix 0.X servers as 0.8.X and 0.9.X, those | |
197 | are the box2d tests (because this datatype simply is missing on those | |
198 | releases), as well as 22 skipped tests for some geometry representations | |
199 | that those old releases do not support. This is a PostGIS server side | |
200 | problem as the server fails to parse some OpenGIS compliant WKT | |
201 | representations, and structurally (but not geometrically or topologically) | |
202 | mangles some other geometries. They are unlikely to be fixed in those | |
203 | releases as users should migrate to PostGIS 1.0. | |
204 | ||
205 | The Autoregister Test needs a pgjdbc version 8.0 or newer, and will | |
206 | simply do nothing with older pgjdbc versions. | |
207 | ||
208 | If you get any failure messages in the online tests, check whether | |
209 | your really fulfil the prerequisites above. If yes, please contact | |
210 | the PostGIS developer list. | |
211 | ||
212 | ||
213 | * What about the JTS stuff * | |
214 | ||
215 | There's beta support for the JTS 1.6 geometry implementations instead of the | |
216 | native PostGIS classes on the java client side. Simply add jts_1.6.jar to your | |
217 | CLASSPATH, "make postgis_jts" and use at your own risk. | |
218 | ||
219 | ||
220 | * How can I contact you? * | |
221 | ||
222 | Well, the best place are the official PostGIS mailing lists for PostGIS, | |
223 | subscription information is linked at: | |
224 | ||
225 | http://postgis.net/ | |
226 | ||
227 | If you want to report errors, please try to send us all the details we need | |
228 | to reproduce your problem. A small, self-contained test case would be best. | |
229 | ||
230 | ||
231 | * Phew. That's all? * | |
232 | ||
233 | Yes. For now, at least. | |
234 | ||
235 | Happy Coding! |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
2 | <modelVersion>4.0.0</modelVersion> | |
3 | ||
4 | <parent> | |
5 | <groupId>net.postgis</groupId> | |
6 | <artifactId>postgis-java-aggregator</artifactId> | |
7 | <version>2.5.0</version> | |
8 | </parent> | |
9 | ||
10 | <artifactId>postgis-jdbc</artifactId> | |
11 | <version>2.5.0</version> | |
12 | <packaging>jar</packaging> | |
13 | ||
14 | <name>Postgis JDBC Driver</name> | |
15 | <description>PostGIS adds support for geographic objects to the PostgreSQL object-relational database.</description> | |
16 | ||
17 | <properties /> | |
18 | ||
19 | <dependencies> | |
20 | <dependency> | |
21 | <groupId>net.postgis</groupId> | |
22 | <artifactId>postgis-geometry</artifactId> | |
23 | <version>2.5.0</version> | |
24 | </dependency> | |
25 | <dependency> | |
26 | <groupId>org.postgresql</groupId> | |
27 | <artifactId>postgresql</artifactId> | |
28 | <version>${dependency.postgresql-jdbc.version}</version> | |
29 | </dependency> | |
30 | <dependency> | |
31 | <groupId>net.postgis.tools</groupId> | |
32 | <artifactId>test-utils</artifactId> | |
33 | <version>2.5.0</version> | |
34 | <scope>test</scope> | |
35 | </dependency> | |
36 | </dependencies> | |
37 | ||
38 | <build> | |
39 | <resources> | |
40 | <resource> | |
41 | <directory>src/main/resources</directory> | |
42 | <filtering>true</filtering> | |
43 | </resource> | |
44 | </resources> | |
45 | <testResources> | |
46 | <testResource> | |
47 | <directory>src/test/resources</directory> | |
48 | </testResource> | |
49 | <testResource> | |
50 | <directory>src/test/resources-filtered</directory> | |
51 | <filtering>true</filtering> | |
52 | </testResource> | |
53 | </testResources> | |
54 | <plugins> | |
55 | <plugin> | |
56 | <groupId>org.apache.maven.plugins</groupId> | |
57 | <artifactId>maven-failsafe-plugin</artifactId> | |
58 | <executions> | |
59 | <execution> | |
60 | <id>integration-tests</id> | |
61 | <goals> | |
62 | <goal>integration-test</goal> | |
63 | <goal>verify</goal> | |
64 | </goals> | |
65 | <configuration> | |
66 | <skip>${maven.integration.test.skip}</skip> | |
67 | <forkCount>${failsafe.forkCount}</forkCount> | |
68 | <useSystemClassLoader>${failsafe.useSystemClassLoader}</useSystemClassLoader> | |
69 | <suiteXmlFiles> | |
70 | <suiteXmlFile>${project.build.testOutputDirectory}/testng-it.xml</suiteXmlFile> | |
71 | </suiteXmlFiles> | |
72 | </configuration> | |
73 | </execution> | |
74 | </executions> | |
75 | </plugin> | |
76 | <plugin> | |
77 | <groupId>org.apache.maven.plugins</groupId> | |
78 | <artifactId>maven-surefire-plugin</artifactId> | |
79 | <configuration> | |
80 | <skip>${maven.test.skip}</skip> | |
81 | <forkCount>${surefire.forkCount}</forkCount> | |
82 | <useSystemClassLoader>${surefire.useSystemClassLoader}</useSystemClassLoader> | |
83 | <suiteXmlFiles> | |
84 | <suiteXmlFile>${project.build.testOutputDirectory}/testng.xml</suiteXmlFile> | |
85 | </suiteXmlFiles> | |
86 | </configuration> | |
87 | </plugin> | |
88 | </plugins> | |
89 | </build> | |
90 | ||
91 | </project> |
0 | /* | |
1 | * TestAutoregister.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package examples; | |
26 | ||
27 | import org.postgis.PGbox2d; | |
28 | import org.postgis.PGbox3d; | |
29 | import org.postgis.PGgeometry; | |
30 | import org.postgresql.Driver; | |
31 | import org.postgresql.util.PGobject; | |
32 | ||
33 | import java.sql.Connection; | |
34 | import java.sql.DriverManager; | |
35 | import java.sql.ResultSet; | |
36 | import java.sql.SQLException; | |
37 | import java.sql.Statement; | |
38 | ||
39 | /** | |
40 | * This test program tests whether the autoregistration of PostGIS data types | |
41 | * within the pgjdbc driver was successful. This is supposed to work with | |
42 | * pgjdbc.jar version 8.0 and newer, and thus refuses to work with older pgjdbc | |
43 | * versions. (But it will work fine against older servers.) It also checks for | |
44 | * postgis version to know whether box2d is available. | |
45 | */ | |
46 | public class TestAutoregister { | |
47 | ||
48 | public static void main(String[] args) { | |
49 | String dburl = null; | |
50 | String dbuser = null; | |
51 | String dbpass = null; | |
52 | ||
53 | if (args.length == 3) { | |
54 | System.out.println("Testing proper auto-registration"); | |
55 | dburl = args[0]; | |
56 | dbuser = args[1]; | |
57 | dbpass = args[2]; | |
58 | } else { | |
59 | System.err.println("Usage: java examples/TestParser dburl user pass"); | |
60 | System.exit(1); | |
61 | // Signal the compiler that code flow ends here. | |
62 | return; | |
63 | } | |
64 | ||
65 | System.out.println("Driver version: " + Driver.getVersion()); | |
66 | int major; | |
67 | try { | |
68 | major = new Driver().getMajorVersion(); | |
69 | } catch (Exception e) { | |
70 | System.err.println("Cannot create Driver instance: " + e.getMessage()); | |
71 | System.exit(1); | |
72 | return; | |
73 | } | |
74 | ||
75 | if (major < 8) { | |
76 | System.err.println("Your pgdjbc " + major | |
77 | + ".X is too old, it does not support autoregistration!"); | |
78 | return; | |
79 | } | |
80 | ||
81 | System.out.println("Creating JDBC connection to " + dburl); | |
82 | Connection conn = null; | |
83 | Statement stat = null; | |
84 | try { | |
85 | conn = DriverManager.getConnection(dburl, dbuser, dbpass); | |
86 | stat = conn.createStatement(); | |
87 | } catch (SQLException e) { | |
88 | System.err.println("Connection initialization failed, aborting."); | |
89 | e.printStackTrace(); | |
90 | System.exit(1); | |
91 | // signal the compiler that code flow ends here: | |
92 | throw new AssertionError(); | |
93 | } | |
94 | ||
95 | int postgisServerMajor = 0; | |
96 | try { | |
97 | postgisServerMajor = getPostgisMajor(stat); | |
98 | } catch (SQLException e) { | |
99 | System.err.println("Error fetching PostGIS version: " + e.getMessage()); | |
100 | System.err.println("Is PostGIS really installed in the database?"); | |
101 | System.exit(1); | |
102 | // signal the compiler that code flow ends here: | |
103 | throw new AssertionError(); | |
104 | } | |
105 | ||
106 | System.out.println("PostGIS Version: " + postgisServerMajor); | |
107 | ||
108 | PGobject result = null; | |
109 | ||
110 | /* Test geometries */ | |
111 | try { | |
112 | ResultSet rs = stat.executeQuery("SELECT 'POINT(1 2)'::geometry"); | |
113 | rs.next(); | |
114 | result = (PGobject) rs.getObject(1); | |
115 | if (result instanceof PGgeometry) { | |
116 | System.out.println("PGgeometry successful!"); | |
117 | } else { | |
118 | System.out.println("PGgeometry failed!"); | |
119 | } | |
120 | } catch (SQLException e) { | |
121 | System.err.println("Selecting geometry failed: " + e.getMessage()); | |
122 | System.exit(1); | |
123 | // Signal the compiler that code flow ends here. | |
124 | return; | |
125 | } | |
126 | ||
127 | /* Test box3d */ | |
128 | try { | |
129 | ResultSet rs = stat.executeQuery("SELECT 'BOX3D(1 2 3, 4 5 6)'::box3d"); | |
130 | rs.next(); | |
131 | result = (PGobject) rs.getObject(1); | |
132 | if (result instanceof PGbox3d) { | |
133 | System.out.println("Box3d successful!"); | |
134 | } else { | |
135 | System.out.println("Box3d failed!"); | |
136 | } | |
137 | } catch (SQLException e) { | |
138 | System.err.println("Selecting box3d failed: " + e.getMessage()); | |
139 | System.exit(1); | |
140 | // Signal the compiler that code flow ends here. | |
141 | return; | |
142 | } | |
143 | ||
144 | /* Test box2d if appropriate */ | |
145 | if (postgisServerMajor < 1) { | |
146 | System.out.println("PostGIS version is too old, skipping box2ed test"); | |
147 | System.err.println("PostGIS version is too old, skipping box2ed test"); | |
148 | } else { | |
149 | try { | |
150 | ResultSet rs = stat.executeQuery("SELECT 'BOX(1 2,3 4)'::box2d"); | |
151 | rs.next(); | |
152 | result = (PGobject) rs.getObject(1); | |
153 | if (result instanceof PGbox2d) { | |
154 | System.out.println("Box2d successful!"); | |
155 | } else { | |
156 | System.out.println("Box2d failed! " + result.getClass().getName()); | |
157 | } | |
158 | } catch (SQLException e) { | |
159 | System.err.println("Selecting box2d failed: " + e.getMessage()); | |
160 | System.exit(1); | |
161 | // Signal the compiler that code flow ends here. | |
162 | return; | |
163 | } | |
164 | } | |
165 | ||
166 | System.out.println("Finished."); | |
167 | // If we finished up to here without exitting, we passed all tests. | |
168 | System.err.println("TestAutoregister.java finished without errors."); | |
169 | } | |
170 | ||
171 | public static int getPostgisMajor(Statement stat) throws SQLException { | |
172 | ResultSet rs = stat.executeQuery("SELECT postgis_version()"); | |
173 | rs.next(); | |
174 | String version = rs.getString(1); | |
175 | if (version == null) { | |
176 | throw new SQLException("postgis_version returned NULL!"); | |
177 | } | |
178 | version = version.trim(); | |
179 | int idx = version.indexOf('.'); | |
180 | return Integer.parseInt(version.substring(0, idx)); | |
181 | } | |
182 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
16 | * | |
17 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
18 | */ | |
19 | ||
20 | package org.postgis; | |
21 | ||
22 | ||
23 | import java.sql.Connection; | |
24 | import java.sql.SQLException; | |
25 | import java.util.Properties; | |
26 | import java.util.logging.Level; | |
27 | import java.util.logging.Logger; | |
28 | ||
29 | import org.postgresql.Driver; | |
30 | import org.postgresql.PGConnection; | |
31 | ||
32 | ||
33 | /** | |
34 | * DriverWrapper | |
35 | * | |
36 | * Wraps the PostGreSQL Driver to transparently add the PostGIS Object Classes. | |
37 | * This avoids the need of explicit addDataType() calls from the driver users | |
38 | * side. | |
39 | * | |
40 | * This method currently works with J2EE DataSource implementations, and with | |
41 | * DriverManager framework. | |
42 | * | |
43 | * Simply replace the "jdbc:postgresql:" with a "jdbc:postgresql_postGIS:" in | |
44 | * the jdbc URL. | |
45 | * | |
46 | * When using the drivermanager, you need to initialize DriverWrapper instead of | |
47 | * (or in addition to) org.postgresql.Driver. When using a J2EE DataSource | |
48 | * implementation, set the driver class property in the datasource config, the | |
49 | * following works for jboss: | |
50 | * | |
51 | * <code> | |
52 | * <driver-class>org.postgis.DriverWrapper</driver-class> | |
53 | * </code> | |
54 | * If you don't like or want to use the DriverWrapper, you have two | |
55 | * alternatives, see the README file. | |
56 | * | |
57 | * Also note that the addDataType() methods known from earlier pgjdbc versions | |
58 | * are deprecated in pgjdbc 8.0, see the commented code variants in the | |
59 | * addGisTypes() method. | |
60 | * | |
61 | * This wrapper always uses EWKT as canonical text representation, and thus | |
62 | * works against PostGIS 1.x servers as well as 0.x (tested with 0.8, 0.9 and | |
63 | * 1.0). | |
64 | * | |
65 | * @author {@literal Markus Schaber <markus.schaber@logix-tt.com>} | |
66 | * @see DriverWrapperLW | |
67 | * @see DriverWrapperAutoprobe | |
68 | */ | |
69 | public class DriverWrapper extends Driver { | |
70 | ||
71 | /** The static logger instance. */ | |
72 | protected static final Logger logger = Logger.getLogger("org.postgis.DriverWrapper"); | |
73 | ||
74 | public static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; | |
75 | public static final String POSTGIS_PROTOCOL = "jdbc:postgresql_postGIS:"; | |
76 | public static final String REVISION = "$Revision$"; | |
77 | protected static TypesAdder ta72 = null; | |
78 | protected static TypesAdder ta74 = null; | |
79 | protected static TypesAdder ta80 = null; | |
80 | ||
81 | protected TypesAdder typesAdder; | |
82 | ||
83 | ||
84 | static { | |
85 | try { | |
86 | // Try to register ourself to the DriverManager | |
87 | java.sql.DriverManager.registerDriver(new DriverWrapper()); | |
88 | } catch (SQLException e) { | |
89 | logger.log(Level.WARNING, "Error registering PostGIS Wrapper Driver", e); | |
90 | } | |
91 | } | |
92 | ||
93 | ||
94 | /** | |
95 | * Default constructor. | |
96 | * | |
97 | * This also loads the appropriate TypesAdder for our SQL Driver instance. | |
98 | * | |
99 | * @throws SQLException when a SQLException occurs | |
100 | */ | |
101 | public DriverWrapper() throws SQLException { | |
102 | super(); | |
103 | typesAdder = getTypesAdder(this); | |
104 | // The debug method is @since 7.2 | |
105 | if (super.getMajorVersion() > 8 || super.getMinorVersion() > 1) { | |
106 | logger.fine(this.getClass().getName() + " loaded TypesAdder: " | |
107 | + typesAdder.getClass().getName()); | |
108 | } | |
109 | } | |
110 | ||
111 | ||
112 | protected static TypesAdder getTypesAdder(final Driver d) throws SQLException { | |
113 | if (d.getMajorVersion() == 7) { | |
114 | if (d.getMinorVersion() >= 3) { | |
115 | if (ta74 == null) { | |
116 | ta74 = loadTypesAdder("74"); | |
117 | } | |
118 | return ta74; | |
119 | } else { | |
120 | if (ta72 == null) { | |
121 | ta72 = loadTypesAdder("72"); | |
122 | } | |
123 | return ta72; | |
124 | } | |
125 | } else { | |
126 | if (ta80 == null) { | |
127 | ta80 = loadTypesAdder("80"); | |
128 | } | |
129 | return ta80; | |
130 | } | |
131 | } | |
132 | ||
133 | ||
134 | private static TypesAdder loadTypesAdder(final String version) throws SQLException { | |
135 | try { | |
136 | Class klass = Class.forName("org.postgis.DriverWrapper$TypesAdder" + version); | |
137 | return (TypesAdder) klass.newInstance(); | |
138 | } catch (Exception e) { | |
139 | throw new SQLException("Cannot create TypesAdder instance! " + e.getMessage()); | |
140 | } | |
141 | } | |
142 | ||
143 | ||
144 | /** | |
145 | * Creates a postgresql connection, and then adds the PostGIS data types to it calling addpgtypes(). | |
146 | * | |
147 | * A side-effect of this method is that the specified url parameter may be be changed | |
148 | * | |
149 | * @param url the URL of the database to connect to (may be changed as a side-effect of this method) | |
150 | * @param info a list of arbitrary tag/value pairs as connection arguments | |
151 | * @return a connection to the URL or null if it isnt us | |
152 | * @exception SQLException if a database access error occurs | |
153 | * | |
154 | * @see java.sql.Driver#connect | |
155 | * @see org.postgresql.Driver | |
156 | */ | |
157 | public java.sql.Connection connect(String url, final Properties info) throws SQLException { | |
158 | url = mangleURL(url); | |
159 | Connection result = super.connect(url, info); | |
160 | typesAdder.addGT(result, useLW(result)); | |
161 | return result; | |
162 | } | |
163 | ||
164 | ||
165 | /** | |
166 | * Do we have HexWKB as well known text representation - to be overridden by | |
167 | * subclasses. | |
168 | * | |
169 | * @param result Connection to check | |
170 | * @return true if using EWKB, false otherwise | |
171 | */ | |
172 | protected boolean useLW(final Connection result) { | |
173 | if (result == null) { | |
174 | throw new IllegalArgumentException("null is no valid parameter"); | |
175 | } | |
176 | return false; | |
177 | } | |
178 | ||
179 | ||
180 | /** | |
181 | * Check whether the driver thinks he can handle the given URL. | |
182 | * | |
183 | * A side-effect of this method is that the specified url parameter may be be changed | |
184 | * | |
185 | * @see java.sql.Driver#acceptsURL | |
186 | * @param url the URL of the driver (may be changed as a side-effect of this method) | |
187 | * @return true if this driver accepts the given URL | |
188 | */ | |
189 | public boolean acceptsURL(String url) { | |
190 | try { | |
191 | url = mangleURL(url); | |
192 | } catch (SQLException e) { | |
193 | return false; | |
194 | } | |
195 | return super.acceptsURL(url); | |
196 | } | |
197 | ||
198 | ||
199 | /** | |
200 | * Returns our own CVS version plus postgres Version | |
201 | * | |
202 | * @return String value reprenstation of the version | |
203 | */ | |
204 | public static String getVersion() { | |
205 | return "PostGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); | |
206 | } | |
207 | ||
208 | ||
209 | /* | |
210 | * Here follows the addGISTypes() stuff. This is a little tricky because the | |
211 | * pgjdbc people had several, partially incompatible API changes during 7.2 | |
212 | * and 8.0. We still want to support all those releases, however. | |
213 | * | |
214 | */ | |
215 | /** | |
216 | * adds the JTS/PostGIS Data types to a PG 7.3+ Connection. If you use | |
217 | * PostgreSQL jdbc drivers V8.0 or newer, those methods are deprecated due | |
218 | * to some class loader problems (but still work for now), and you may want | |
219 | * to use the method below instead. | |
220 | * | |
221 | * @param pgconn The PGConnection object to add the types to | |
222 | * @throws SQLException when a SQLException occurs | |
223 | * | |
224 | */ | |
225 | public static void addGISTypes(final PGConnection pgconn) throws SQLException { | |
226 | loadTypesAdder("74").addGT((Connection) pgconn, false); | |
227 | } | |
228 | ||
229 | ||
230 | /** | |
231 | * adds the JTS/PostGIS Data types to a PG 8.0+ Connection. | |
232 | * | |
233 | * @param pgconn The PGConnection object to add the types to | |
234 | * @throws SQLException when a SQLException occurs | |
235 | */ | |
236 | public static void addGISTypes80(final PGConnection pgconn) throws SQLException { | |
237 | loadTypesAdder("80").addGT((Connection) pgconn, false); | |
238 | } | |
239 | ||
240 | ||
241 | /** | |
242 | * adds the JTS/PostGIS Data types to a PG 7.2 Connection. | |
243 | * | |
244 | * @param pgconn The PGConnection object to add the types to | |
245 | * @throws SQLException when a SQLException occurs | |
246 | */ | |
247 | public static void addGISTypes72(final org.postgresql.PGConnection pgconn) throws SQLException { | |
248 | loadTypesAdder("72").addGT((Connection) pgconn, false); | |
249 | } | |
250 | ||
251 | ||
252 | /** | |
253 | * Mangles the PostGIS URL to return the original PostGreSQL URL | |
254 | * | |
255 | * @param url String containing the url to be "mangled" | |
256 | * @return "mangled" string | |
257 | * @throws SQLException when a SQLException occurs | |
258 | */ | |
259 | protected String mangleURL(final String url) throws SQLException { | |
260 | String myProgo = getProtoString(); | |
261 | if (url.startsWith(myProgo)) { | |
262 | return POSTGRES_PROTOCOL + url.substring(myProgo.length()); | |
263 | } else { | |
264 | throw new SQLException("Unknown protocol or subprotocol in url " + url); | |
265 | } | |
266 | } | |
267 | ||
268 | ||
269 | protected String getProtoString() { | |
270 | return POSTGIS_PROTOCOL; | |
271 | } | |
272 | ||
273 | ||
274 | /** Base class for the three typewrapper implementations */ | |
275 | protected abstract static class TypesAdder { | |
276 | public final void addGT(final java.sql.Connection conn, final boolean lw) throws SQLException { | |
277 | if (lw) { | |
278 | addBinaryGeometries(conn); | |
279 | } else { | |
280 | addGeometries(conn); | |
281 | } | |
282 | addBoxen(conn); | |
283 | } | |
284 | ||
285 | public abstract void addGeometries(final Connection conn) throws SQLException; | |
286 | ||
287 | public abstract void addBoxen(final Connection conn) throws SQLException; | |
288 | ||
289 | public abstract void addBinaryGeometries(final Connection conn) throws SQLException; | |
290 | } | |
291 | ||
292 | ||
293 | /** addGISTypes for V7.3 and V7.4 pgjdbc */ | |
294 | protected static final class TypesAdder74 extends TypesAdder { | |
295 | ||
296 | /** {@inheritDoc} */ | |
297 | @Override | |
298 | public void addGeometries(final Connection conn) throws SQLException { | |
299 | PGConnection pgconn = (PGConnection) conn; | |
300 | pgconn.addDataType("geometry", org.postgis.PGgeometry.class); | |
301 | pgconn.addDataType("public.geometry", org.postgis.PGgeometry.class); | |
302 | pgconn.addDataType("\"public\".\"geometry\"", org.postgis.PGgeometry.class); | |
303 | ||
304 | pgconn.addDataType("geography", org.postgis.PGgeography.class); | |
305 | pgconn.addDataType("public.geography", org.postgis.PGgeography.class); | |
306 | pgconn.addDataType("\"public\".\"geography\"", org.postgis.PGgeography.class); | |
307 | } | |
308 | ||
309 | /** {@inheritDoc} */ | |
310 | @Override | |
311 | public void addBoxen(final Connection conn) throws SQLException { | |
312 | PGConnection pgconn = (PGConnection) conn; | |
313 | pgconn.addDataType("box3d", org.postgis.PGbox3d.class); | |
314 | pgconn.addDataType("box2d", org.postgis.PGbox2d.class); | |
315 | } | |
316 | ||
317 | /** {@inheritDoc} */ | |
318 | @Override | |
319 | public void addBinaryGeometries(final Connection conn) throws SQLException { | |
320 | PGConnection pgconn = (PGConnection) conn; | |
321 | pgconn.addDataType("geometry", org.postgis.PGgeometryLW.class); | |
322 | pgconn.addDataType("geography", org.postgis.PGgeographyLW.class); | |
323 | } | |
324 | } | |
325 | ||
326 | ||
327 | /** addGISTypes for V7.2 pgjdbc */ | |
328 | protected static class TypesAdder72 extends TypesAdder { | |
329 | ||
330 | /** {@inheritDoc} */ | |
331 | @Override | |
332 | public void addGeometries(final Connection conn) throws SQLException { | |
333 | org.postgresql.PGConnection pgconn = (org.postgresql.PGConnection) conn; | |
334 | pgconn.addDataType("geometry", org.postgis.PGgeometry.class); | |
335 | pgconn.addDataType("public.geometry", org.postgis.PGgeometry.class); | |
336 | pgconn.addDataType("\"public\".\"geometry\"", org.postgis.PGgeometry.class); | |
337 | ||
338 | pgconn.addDataType("geography", org.postgis.PGgeography.class); | |
339 | pgconn.addDataType("public.geography", org.postgis.PGgeography.class); | |
340 | pgconn.addDataType("\"public\".\"geography\"", org.postgis.PGgeography.class); | |
341 | } | |
342 | ||
343 | /** {@inheritDoc} */ | |
344 | @Override | |
345 | public void addBoxen(final Connection conn) throws SQLException { | |
346 | org.postgresql.PGConnection pgconn = (org.postgresql.PGConnection) conn; | |
347 | pgconn.addDataType("box3d", org.postgis.PGbox3d.class); | |
348 | pgconn.addDataType("box2d", org.postgis.PGbox2d.class); | |
349 | } | |
350 | ||
351 | /** {@inheritDoc} */ | |
352 | @Override | |
353 | public void addBinaryGeometries(final Connection conn) throws SQLException { | |
354 | org.postgresql.PGConnection pgconn = (org.postgresql.PGConnection) conn; | |
355 | pgconn.addDataType("geometry", org.postgis.PGgeometryLW.class); | |
356 | pgconn.addDataType("geography", org.postgis.PGgeographyLW.class); | |
357 | } | |
358 | } | |
359 | ||
360 | ||
361 | /** addGISTypes for V8.0 (and hopefully newer) pgjdbc */ | |
362 | protected static class TypesAdder80 extends TypesAdder { | |
363 | ||
364 | /** {@inheritDoc} */ | |
365 | @Override | |
366 | public void addGeometries(final Connection conn) throws SQLException { | |
367 | PGConnection pgconn = (PGConnection) conn; | |
368 | pgconn.addDataType("geometry", org.postgis.PGgeometry.class); | |
369 | pgconn.addDataType("public.geometry", org.postgis.PGgeometry.class); | |
370 | pgconn.addDataType("\"public\".\"geometry\"", org.postgis.PGgeometry.class); | |
371 | ||
372 | pgconn.addDataType("geography", org.postgis.PGgeometry.class); | |
373 | pgconn.addDataType("public.geography", org.postgis.PGgeometry.class); | |
374 | pgconn.addDataType("\"public\".\"geography\"", org.postgis.PGgeometry.class); | |
375 | } | |
376 | ||
377 | /** {@inheritDoc} */ | |
378 | @Override | |
379 | public void addBoxen(final Connection conn) throws SQLException { | |
380 | PGConnection pgconn = (PGConnection) conn; | |
381 | pgconn.addDataType("box3d", org.postgis.PGbox3d.class); | |
382 | pgconn.addDataType("box2d", org.postgis.PGbox2d.class); | |
383 | } | |
384 | ||
385 | /** {@inheritDoc} */ | |
386 | @Override | |
387 | public void addBinaryGeometries(final Connection conn) throws SQLException { | |
388 | PGConnection pgconn = (PGConnection) conn; | |
389 | pgconn.addDataType("geometry", org.postgis.PGgeometryLW.class); | |
390 | pgconn.addDataType("geography", org.postgis.PGgeographyLW.class); | |
391 | } | |
392 | } | |
393 | ||
394 | ||
395 | /** {@inheritDoc} */ | |
396 | @Override | |
397 | public Logger getParentLogger() { | |
398 | throw new UnsupportedOperationException("Not supported yet."); | |
399 | } | |
400 | ||
401 | ||
402 | } |
0 | /* | |
1 | * DriverWrapperAutoprobe.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Wrapper utility class | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package org.postgis; | |
26 | ||
27 | import org.postgresql.Driver; | |
28 | ||
29 | import java.sql.Connection; | |
30 | import java.sql.ResultSet; | |
31 | import java.sql.SQLException; | |
32 | import java.sql.Statement; | |
33 | import java.util.logging.Level; | |
34 | ||
35 | /** | |
36 | * DriverWrapperAutoprobe | |
37 | * | |
38 | * Wraps the PostGreSQL Driver to transparently add the PostGIS Object Classes. | |
39 | * This avoids the need of explicit addDataType() calls from the driver users | |
40 | * side. | |
41 | * | |
42 | * This DriverWrapper tries to autoprobe the installed PostGIS version to decide | |
43 | * whether to use EWKT or hex encoded EWKB as canonical text representation. It | |
44 | * uses the first PostGIS installation found in your namespace search path (aka | |
45 | * schema search path) on the server side, and this works as long as you do not | |
46 | * access incompatible PostGIS versions that reside in other schemas. | |
47 | * | |
48 | * For usage notes, see DriverWrapper class, but use "jdbc:postgresql_autogis:" | |
49 | * as JDBC url prefix and org.postgis.DriverWrapperAutoprobe as driver class. | |
50 | * | |
51 | * @author {@literal Markus Schaber <markus.schaber@logix-tt.com>} | |
52 | * @see DriverWrapper | |
53 | */ | |
54 | public class DriverWrapperAutoprobe extends DriverWrapper { | |
55 | ||
56 | public static final String POSTGIS_AUTOPROTOCOL = "jdbc:postgresql_autogis:"; | |
57 | public static final String REVISIONAUTO = "$Revision$"; | |
58 | ||
59 | /** | |
60 | * Default constructor. | |
61 | * | |
62 | * @throws SQLException when a SQLExceptin occurs | |
63 | */ | |
64 | public DriverWrapperAutoprobe() throws SQLException { | |
65 | super(); | |
66 | } | |
67 | ||
68 | static { | |
69 | try { | |
70 | // Try to register ourself to the DriverManager | |
71 | java.sql.DriverManager.registerDriver(new DriverWrapperAutoprobe()); | |
72 | } catch (SQLException e) { | |
73 | logger.log(Level.WARNING, "Error registering PostGIS LW Wrapper Driver", e); | |
74 | } | |
75 | } | |
76 | ||
77 | protected String getProtoString() { | |
78 | return POSTGIS_AUTOPROTOCOL; | |
79 | } | |
80 | ||
81 | protected boolean useLW(Connection conn) { | |
82 | try { | |
83 | return supportsEWKB(conn); | |
84 | } catch (SQLException e) { | |
85 | // fail safe default | |
86 | return false; | |
87 | } | |
88 | } | |
89 | ||
90 | /** | |
91 | * Returns our own CVS version plus postgres Version | |
92 | * | |
93 | * @return String value reprenstation of the version | |
94 | */ | |
95 | public static String getVersion() { | |
96 | return "PostGisWrapperAutoprobe " + REVISIONAUTO + ", wrapping " + Driver.getVersion(); | |
97 | } | |
98 | ||
99 | public static boolean supportsEWKB(Connection conn) throws SQLException { | |
100 | Statement stat = conn.createStatement(); | |
101 | ResultSet rs = stat.executeQuery("SELECT postgis_version()"); | |
102 | rs.next(); | |
103 | String version = rs.getString(1); | |
104 | rs.close(); | |
105 | stat.close(); | |
106 | if (version == null) { | |
107 | throw new SQLException("postgis_version returned NULL!"); | |
108 | } | |
109 | version = version.trim(); | |
110 | int idx = version.indexOf('.'); | |
111 | int majorVersion = Integer.parseInt(version.substring(0, idx)); | |
112 | return majorVersion >= 1; | |
113 | } | |
114 | } |
0 | /* | |
1 | * DriverWrapperLW.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Wrapper utility class | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package org.postgis; | |
26 | ||
27 | import org.postgresql.Driver; | |
28 | ||
29 | import java.sql.Connection; | |
30 | import java.sql.SQLException; | |
31 | import java.util.logging.Level; | |
32 | ||
33 | /** | |
34 | * DriverWrapperLW | |
35 | * | |
36 | * Wraps the PostGreSQL Driver to transparently add the PostGIS Object Classes. | |
37 | * This avoids the need of explicit addDataType() calls from the driver users | |
38 | * side. | |
39 | * | |
40 | * This DriverWrapper subclass always uses hex encoded EWKB as canonical text | |
41 | * representation, and thus only works against PostGIS 1.x servers and newer. | |
42 | * | |
43 | * For usage notes, see DriverWrapper class, but use "jdbc:postgresql_lwgis:" as | |
44 | * JDBC url prefix and org.postgis.DriverWrapperLW as driver class. | |
45 | * | |
46 | * @author {@literal Markus Schaber <markus.schaber@logix-tt.com>} | |
47 | * @see DriverWrapper | |
48 | */ | |
49 | public class DriverWrapperLW extends DriverWrapper { | |
50 | ||
51 | public static final String POSTGIS_LWPROTOCOL = "jdbc:postgresql_lwgis:"; | |
52 | public static final String REVISIONLW = "$Revision$"; | |
53 | ||
54 | /** | |
55 | * Default constructor. | |
56 | * | |
57 | * @throws SQLException when a SQLException occurs | |
58 | */ | |
59 | public DriverWrapperLW() throws SQLException { | |
60 | super(); | |
61 | } | |
62 | ||
63 | static { | |
64 | try { | |
65 | // Try to register ourself to the DriverManager | |
66 | java.sql.DriverManager.registerDriver(new DriverWrapperLW()); | |
67 | } catch (SQLException e) { | |
68 | logger.log(Level.WARNING, "Error registering PostGIS LW Wrapper Driver", e); | |
69 | } | |
70 | } | |
71 | ||
72 | protected String getProtoString() { | |
73 | return POSTGIS_LWPROTOCOL; | |
74 | } | |
75 | ||
76 | protected boolean useLW(Connection result) { | |
77 | return true; | |
78 | } | |
79 | ||
80 | /** | |
81 | * Returns our own CVS version plus postgres Version | |
82 | * | |
83 | * @return String value reprenstation of the version | |
84 | */ | |
85 | public static String getVersion() { | |
86 | return "PostGisWrapperLW " + REVISIONLW + ", wrapping " + Driver.getVersion(); | |
87 | } | |
88 | } |
0 | /* | |
1 | * PGbox2d.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - bounding box model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | public class PGbox2d extends PGboxbase { | |
32 | /* JDK 1.5 Serialization */ | |
33 | private static final long serialVersionUID = 0x100; | |
34 | ||
35 | public PGbox2d() { | |
36 | super(); | |
37 | } | |
38 | ||
39 | public PGbox2d(Point llb, Point urt) { | |
40 | super(llb, urt); | |
41 | } | |
42 | ||
43 | public PGbox2d(String value) throws SQLException { | |
44 | super(value); | |
45 | } | |
46 | ||
47 | public void setValue(String value) throws SQLException { | |
48 | super.setValue(value); | |
49 | ||
50 | if (llb.dimension != 2 || urt.dimension != 2) { | |
51 | throw new SQLException("PGbox2d is only allowed to have 2 dimensions!"); | |
52 | } | |
53 | } | |
54 | ||
55 | public String getPrefix() { | |
56 | return "BOX"; | |
57 | } | |
58 | ||
59 | public String getPGtype() { | |
60 | return "box2d"; | |
61 | } | |
62 | ||
63 | protected PGboxbase newInstance() { | |
64 | return new PGbox2d(); | |
65 | } | |
66 | } |
0 | /* | |
1 | * PGbox3d.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - bounding box model | |
4 | * | |
5 | * | |
6 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
7 | * | |
8 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
9 | * | |
10 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
11 | * | |
12 | * This library is free software; you can redistribute it and/or | |
13 | * modify it under the terms of the GNU Lesser General Public | |
14 | * License as published by the Free Software Foundation; either | |
15 | * version 2.1 of the License, or (at your option) any later version. | |
16 | * | |
17 | * This library is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
20 | * Lesser General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU Lesser General Public | |
23 | * License along with this library; if not, write to the Free Software | |
24 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
25 | * | |
26 | */ | |
27 | ||
28 | package org.postgis; | |
29 | ||
30 | import java.sql.SQLException; | |
31 | ||
32 | public class PGbox3d extends PGboxbase { | |
33 | /* JDK 1.5 Serialization */ | |
34 | private static final long serialVersionUID = 0x100; | |
35 | ||
36 | public PGbox3d() { | |
37 | super(); | |
38 | } | |
39 | ||
40 | public PGbox3d(Point llb, Point urt) { | |
41 | super(llb, urt); | |
42 | } | |
43 | ||
44 | public PGbox3d(String value) throws SQLException { | |
45 | super(value); | |
46 | } | |
47 | ||
48 | public String getPrefix() { | |
49 | return ("BOX3D"); | |
50 | } | |
51 | ||
52 | public String getPGtype() { | |
53 | return ("box3d"); | |
54 | } | |
55 | ||
56 | protected PGboxbase newInstance() { | |
57 | return new PGbox3d(); | |
58 | } | |
59 | } |
0 | /* | |
1 | * PGboxbase.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - bounding box model | |
4 | * | |
5 | * | |
6 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
7 | * | |
8 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
9 | * | |
10 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
11 | * | |
12 | * This library is free software; you can redistribute it and/or | |
13 | * modify it under the terms of the GNU Lesser General Public | |
14 | * License as published by the Free Software Foundation; either | |
15 | * version 2.1 of the License, or (at your option) any later version. | |
16 | * | |
17 | * This library is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
20 | * Lesser General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU Lesser General Public | |
23 | * License along with this library; if not, write to the Free Software | |
24 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
25 | * | |
26 | */ | |
27 | ||
28 | package org.postgis; | |
29 | ||
30 | import org.postgresql.util.PGobject; | |
31 | ||
32 | import java.sql.SQLException; | |
33 | import java.util.List; | |
34 | ||
35 | /* | |
36 | * Updates Oct 2002 - data members made private - getLLB() and getURT() methods | |
37 | * added | |
38 | */ | |
39 | ||
40 | public abstract class PGboxbase extends PGobject { | |
41 | /* JDK 1.5 Serialization */ | |
42 | private static final long serialVersionUID = 0x100; | |
43 | ||
44 | /** | |
45 | * The lower left bottom corner of the box. | |
46 | */ | |
47 | protected Point llb; | |
48 | ||
49 | /** | |
50 | * The upper right top corner of the box. | |
51 | */ | |
52 | protected Point urt; | |
53 | ||
54 | /** | |
55 | * The Prefix we have in WKT rep. | |
56 | * | |
57 | * I use an abstract method here so we do not need to replicate the String | |
58 | * object in every instance. | |
59 | * | |
60 | * @return the prefix, as a string | |
61 | */ | |
62 | public abstract String getPrefix(); | |
63 | ||
64 | /** | |
65 | * The Postgres type we have (same construct as getPrefix()) | |
66 | * | |
67 | * @return String containing the name of the type for this box. | |
68 | */ | |
69 | public abstract String getPGtype(); | |
70 | ||
71 | public PGboxbase() { | |
72 | this.setType(getPGtype()); | |
73 | } | |
74 | ||
75 | public PGboxbase(Point llb, Point urt) { | |
76 | this(); | |
77 | this.llb = llb; | |
78 | this.urt = urt; | |
79 | } | |
80 | ||
81 | public PGboxbase(String value) throws SQLException { | |
82 | this(); | |
83 | setValue(value); | |
84 | } | |
85 | ||
86 | public void setValue(String value) throws SQLException { | |
87 | int srid = Geometry.UNKNOWN_SRID; | |
88 | value = value.trim(); | |
89 | if (value.startsWith("SRID=")) { | |
90 | String[] temp = GeometryBuilder.splitSRID(value); | |
91 | value = temp[1].trim(); | |
92 | srid = Geometry.parseSRID(Integer.parseInt(temp[0].substring(5))); | |
93 | } | |
94 | String myPrefix = getPrefix(); | |
95 | if (value.startsWith(myPrefix)) { | |
96 | value = value.substring(myPrefix.length()).trim(); | |
97 | } | |
98 | String valueNoParans = GeometryTokenizer.removeLeadingAndTrailingStrings(value.trim(), "(", ")"); | |
99 | List<String> tokens = GeometryTokenizer.tokenize(valueNoParans, ','); | |
100 | llb = new Point(tokens.get(0)); | |
101 | urt = new Point(tokens.get(1)); | |
102 | if (srid != Geometry.UNKNOWN_SRID) { | |
103 | llb.setSrid(srid); | |
104 | urt.setSrid(srid); | |
105 | } | |
106 | } | |
107 | ||
108 | public String getValue() { | |
109 | StringBuffer sb = new StringBuffer(); | |
110 | outerWKT(sb); | |
111 | return sb.toString(); | |
112 | } | |
113 | ||
114 | private void outerWKT(StringBuffer sb) { | |
115 | sb.append(getPrefix()); | |
116 | sb.append('('); | |
117 | llb.innerWKT(sb); | |
118 | sb.append(','); | |
119 | urt.innerWKT(sb); | |
120 | sb.append(')'); | |
121 | } | |
122 | ||
123 | /** | |
124 | * Unlike geometries, toString() does _not_ contain the srid, as server-side | |
125 | * PostGIS cannot parse this. | |
126 | * | |
127 | * @return String representation of this box | |
128 | */ | |
129 | public String toString() { | |
130 | return getValue(); | |
131 | } | |
132 | ||
133 | /** | |
134 | * Returns the lower left bottom corner of the box as a Point object | |
135 | * | |
136 | * @return lower left bottom corner of this box | |
137 | */ | |
138 | public Point getLLB() { | |
139 | return llb; | |
140 | } | |
141 | ||
142 | /** | |
143 | * Returns the upper right top corner of the box as a Point object | |
144 | * | |
145 | * @return upper right top corner of this box | |
146 | */ | |
147 | public Point getURT() { | |
148 | return urt; | |
149 | } | |
150 | ||
151 | public boolean equals(Object other) { | |
152 | if (other instanceof PGboxbase) { | |
153 | PGboxbase otherbox = (PGboxbase) other; | |
154 | return (compareLazyDim(this.llb, otherbox.llb) && compareLazyDim(this.urt, otherbox.urt)); | |
155 | } | |
156 | return false; | |
157 | } | |
158 | ||
159 | /** | |
160 | * Compare two coordinates with lazy dimension checking. | |
161 | * | |
162 | * As the Server always returns Box3D with three dimensions, z==0 equals | |
163 | * dimensions==2 | |
164 | * | |
165 | * @param first First of two points to be compared | |
166 | * @param second Second of two points to be compared | |
167 | * @return true if the points are the same, false otherwise | |
168 | * | |
169 | */ | |
170 | protected static boolean compareLazyDim(Point first, Point second) { | |
171 | return first.x == second.x | |
172 | && first.y == second.y | |
173 | && (((first.dimension == 2 || first.z == 0.0) && (second.dimension == 2 || second.z == 0)) || (first.z == second.z)); | |
174 | } | |
175 | ||
176 | public Object clone() { | |
177 | PGboxbase obj = newInstance(); | |
178 | obj.llb = this.llb; | |
179 | obj.urt = this.urt; | |
180 | obj.setType(type); | |
181 | return obj; | |
182 | } | |
183 | ||
184 | /** | |
185 | * Obtain a new instance of a PGboxbase | |
186 | * | |
187 | * We could have used this.getClass().newInstance() here, but this forces us | |
188 | * dealing with InstantiationException and IllegalAccessException. Due to | |
189 | * the PGObject.clone() brokennes that does not allow clone() to throw | |
190 | * CloneNotSupportedException, we cannot even pass this exceptions down to | |
191 | * callers in a sane way. | |
192 | * | |
193 | * @return a new instance of PGboxbase | |
194 | */ | |
195 | protected abstract PGboxbase newInstance(); | |
196 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
16 | * | |
17 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
18 | * | |
19 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
20 | */ | |
21 | ||
22 | package org.postgis; | |
23 | ||
24 | ||
25 | import org.postgis.binary.BinaryParser; | |
26 | import org.postgresql.util.PGobject; | |
27 | ||
28 | import java.sql.SQLException; | |
29 | ||
30 | ||
31 | /** | |
32 | * A PostgreSQL JDBC PGobject extension data type modeling a "geo" type. | |
33 | * | |
34 | * This class serves as a common superclass for classes such as PGgeometry and PGgeography which model | |
35 | * more specific type semantics. | |
36 | * | |
37 | * @author Phillip Ross | |
38 | */ | |
39 | public class PGgeo extends PGobject { | |
40 | ||
41 | private static final long serialVersionUID = -3181366908975582090L; | |
42 | ||
43 | /** The encapsulated geometry. */ | |
44 | Geometry geometry; | |
45 | ||
46 | ||
47 | /** Instantiate with default state. */ | |
48 | protected PGgeo() { | |
49 | } | |
50 | ||
51 | ||
52 | /** | |
53 | * Instantiate with the specified state. | |
54 | * | |
55 | * @param geometry the geometry to instantiate with | |
56 | */ | |
57 | public PGgeo(final Geometry geometry) { | |
58 | this(); | |
59 | this.geometry = geometry; | |
60 | } | |
61 | ||
62 | ||
63 | /** | |
64 | * Instantiate with the specified state. | |
65 | * | |
66 | * @param value the value to instantiate with | |
67 | */ | |
68 | public PGgeo(final String value) throws SQLException { | |
69 | this(); | |
70 | setValue(value); | |
71 | } | |
72 | ||
73 | ||
74 | /** {@inheritDoc} */ | |
75 | @Override | |
76 | public String getValue() { | |
77 | return geometry.toString(); | |
78 | } | |
79 | ||
80 | ||
81 | /** {@inheritDoc} */ | |
82 | @Override | |
83 | public void setValue(final String value) throws SQLException { | |
84 | geometry = GeometryBuilder.geomFromString(value, new BinaryParser()); | |
85 | } | |
86 | ||
87 | ||
88 | /** | |
89 | * Get the encapsulated geometry. | |
90 | * | |
91 | * @return the encapsulated geomtery | |
92 | */ | |
93 | public Geometry getGeometry() { | |
94 | return geometry; | |
95 | } | |
96 | ||
97 | ||
98 | /** | |
99 | * Set the encapsulated geometry. | |
100 | * | |
101 | * @param geometry the encapsulated geometry | |
102 | */ | |
103 | public void setGeometry(final Geometry geometry) { | |
104 | this.geometry = geometry; | |
105 | } | |
106 | ||
107 | ||
108 | /** | |
109 | * Get the type of the encapsulated geometry. | |
110 | * | |
111 | * @return the type of the encapsulated geometry | |
112 | */ | |
113 | public int getGeoType() { | |
114 | return geometry.type; | |
115 | } | |
116 | ||
117 | ||
118 | /** {@inheritDoc} */ | |
119 | @Override | |
120 | public String toString() { | |
121 | return geometry.toString(); | |
122 | } | |
123 | ||
124 | ||
125 | /** {@inheritDoc} */ | |
126 | @Override | |
127 | public Object clone() { | |
128 | return new PGgeo(geometry); | |
129 | } | |
130 | ||
131 | ||
132 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
16 | * | |
17 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
18 | * | |
19 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
20 | */ | |
21 | ||
22 | package org.postgis; | |
23 | ||
24 | ||
25 | import java.sql.SQLException; | |
26 | ||
27 | ||
28 | /** | |
29 | * A PostgreSQL JDBC PGobject extension data type modeling the geography type. | |
30 | * | |
31 | * @author Phillip Ross | |
32 | */ | |
33 | public class PGgeography extends PGgeo { | |
34 | ||
35 | private static final long serialVersionUID = 3796853960196603896L; | |
36 | ||
37 | ||
38 | /** Instantiate with default state. */ | |
39 | public PGgeography() { | |
40 | super(); | |
41 | setType("geography"); | |
42 | } | |
43 | ||
44 | ||
45 | /** | |
46 | * Instantiate with the specified state. | |
47 | * | |
48 | * @param geometry the geometry to instantiate with | |
49 | */ | |
50 | public PGgeography(final Geometry geometry) { | |
51 | this(); | |
52 | this.geometry = geometry; | |
53 | setType("geography"); | |
54 | } | |
55 | ||
56 | ||
57 | /** | |
58 | * Instantiate with the specified state. | |
59 | * | |
60 | * @param value the value to instantiate with | |
61 | */ | |
62 | public PGgeography(final String value) throws SQLException { | |
63 | this(); | |
64 | setValue(value); | |
65 | setType("geography"); | |
66 | } | |
67 | ||
68 | ||
69 | /** {@inheritDoc} */ | |
70 | @Override | |
71 | public Object clone() { | |
72 | return new PGgeography(geometry); | |
73 | } | |
74 | ||
75 | ||
76 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
16 | * | |
17 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
18 | */ | |
19 | ||
20 | package org.postgis; | |
21 | ||
22 | ||
23 | import org.postgis.binary.BinaryWriter; | |
24 | ||
25 | import java.sql.SQLException; | |
26 | ||
27 | ||
28 | /** | |
29 | * A PostgreSQL JDBC PGobject extension data type modeling the geography type. | |
30 | * | |
31 | * The hex-encoded EWKB format is used to communicate with the backend, which is much more efficient, | |
32 | * but only works with Lwgeom enabled PostGIS (1.0.0 and up). | |
33 | * | |
34 | * @author Phillip Ross | |
35 | */ | |
36 | public class PGgeographyLW extends PGgeography { | |
37 | ||
38 | private static final long serialVersionUID = 7717856818804158022L; | |
39 | ||
40 | /** The binary writer to be used for serializing geometry to a PGobject value. */ | |
41 | BinaryWriter bw = new BinaryWriter(); | |
42 | ||
43 | ||
44 | /** Instantiate with default state. */ | |
45 | public PGgeographyLW() { | |
46 | super(); | |
47 | } | |
48 | ||
49 | /** | |
50 | * Instantiate with the specified state. | |
51 | * | |
52 | * @param geometry the geometry to instantiate with | |
53 | */ | |
54 | public PGgeographyLW(final Geometry geometry) { | |
55 | super(geometry); | |
56 | } | |
57 | ||
58 | ||
59 | /** | |
60 | * Instantiate with the specified state. | |
61 | * | |
62 | * @param value the value to instantiate with | |
63 | */ | |
64 | public PGgeographyLW(final String value) throws SQLException { | |
65 | super(value); | |
66 | } | |
67 | ||
68 | ||
69 | /** {@inheritDoc} */ | |
70 | @Override | |
71 | public String getValue() { | |
72 | return bw.writeHexed(geometry); | |
73 | } | |
74 | ||
75 | ||
76 | /** {@inheritDoc} */ | |
77 | @Override | |
78 | public Object clone() { | |
79 | return new PGgeographyLW(geometry); | |
80 | } | |
81 | ||
82 | ||
83 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
16 | * | |
17 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
18 | * | |
19 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
20 | */ | |
21 | ||
22 | package org.postgis; | |
23 | ||
24 | ||
25 | import java.sql.SQLException; | |
26 | ||
27 | ||
28 | /** | |
29 | * A PostgreSQL JDBC PGobject extension data type modeling the geometry type. | |
30 | * | |
31 | * @author Phillip Ross | |
32 | */ | |
33 | public class PGgeometry extends PGgeo { | |
34 | ||
35 | private static final long serialVersionUID = 4116907189503026815L; | |
36 | ||
37 | ||
38 | /** Instantiate with default state. */ | |
39 | public PGgeometry() { | |
40 | super(); | |
41 | setType("geometry"); | |
42 | } | |
43 | ||
44 | ||
45 | /** | |
46 | * Instantiate with the specified state. | |
47 | * | |
48 | * @param geometry the geometry to instantiate with | |
49 | */ | |
50 | public PGgeometry(final Geometry geometry) { | |
51 | super(geometry); | |
52 | setType("geometry"); | |
53 | } | |
54 | ||
55 | ||
56 | /** | |
57 | * Instantiate with the specified state. | |
58 | * | |
59 | * @param value the value to instantiate with | |
60 | */ | |
61 | public PGgeometry(final String value) throws SQLException { | |
62 | super(value); | |
63 | setType("geometry"); | |
64 | } | |
65 | ||
66 | ||
67 | /** {@inheritDoc} */ | |
68 | @Override | |
69 | public Object clone() { | |
70 | return new PGgeometry(geometry); | |
71 | } | |
72 | ||
73 | ||
74 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
16 | * | |
17 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
18 | */ | |
19 | ||
20 | package org.postgis; | |
21 | ||
22 | ||
23 | import org.postgis.binary.BinaryWriter; | |
24 | ||
25 | import java.sql.SQLException; | |
26 | ||
27 | ||
28 | /** | |
29 | * A PostgreSQL JDBC PGobject extension data type modeling the geometry type. | |
30 | * | |
31 | * The hex-encoded EWKB format is used to communicate with the backend, which is much more efficient, | |
32 | * but only works with Lwgeom enabled PostGIS (1.0.0 and up). | |
33 | * | |
34 | * @author Phillip Ross | |
35 | */ | |
36 | public class PGgeometryLW extends PGgeometry { | |
37 | ||
38 | private static final long serialVersionUID = -7774502289413094862L; | |
39 | ||
40 | /** The binary writer to be used for serializing geometry to a PGobject value. */ | |
41 | BinaryWriter bw = new BinaryWriter(); | |
42 | ||
43 | ||
44 | /** Instantiate with default state. */ | |
45 | public PGgeometryLW() { | |
46 | super(); | |
47 | } | |
48 | ||
49 | ||
50 | /** | |
51 | * Instantiate with the specified state. | |
52 | * | |
53 | * @param geometry the geometry to instantiate with | |
54 | */ | |
55 | public PGgeometryLW(final Geometry geometry) { | |
56 | super(geometry); | |
57 | } | |
58 | ||
59 | ||
60 | /** | |
61 | * Instantiate with the specified state. | |
62 | * | |
63 | * @param value the value to instantiate with | |
64 | */ | |
65 | public PGgeometryLW(final String value) throws SQLException { | |
66 | super(value); | |
67 | } | |
68 | ||
69 | ||
70 | /** {@inheritDoc} */ | |
71 | @Override | |
72 | public String getValue() { | |
73 | return bw.writeHexed(geometry); | |
74 | } | |
75 | ||
76 | ||
77 | /** {@inheritDoc} */ | |
78 | @Override | |
79 | public Object clone() { | |
80 | return new PGgeometryLW(geometry); | |
81 | } | |
82 | ||
83 | ||
84 | } |
0 | /* | |
1 | * Version.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - current version identification | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package org.postgis; | |
26 | ||
27 | ||
28 | import java.io.IOException; | |
29 | import java.util.Properties; | |
30 | ||
31 | ||
32 | /** Corresponds to the appropriate PostGIS that carried this source */ | |
33 | public class Version { | |
34 | ||
35 | /** We read our version information from this resource... */ | |
36 | private static final String RESOURCE_FILENAME = "org/postgis/version.properties"; | |
37 | ||
38 | private static final String VERSION_PROPERTY_NAME = "VERSION"; | |
39 | ||
40 | public static final String VERSION; | |
41 | ||
42 | /** The major version */ | |
43 | public static final int MAJOR; | |
44 | ||
45 | /** The minor version */ | |
46 | public static final int MINOR; | |
47 | ||
48 | /** | |
49 | * The micro version, usually a number including possibly textual suffixes | |
50 | * like RC3. | |
51 | */ | |
52 | public static final String MICRO; | |
53 | ||
54 | static { | |
55 | int major = -1; | |
56 | int minor = -1; | |
57 | String micro = null; | |
58 | String version = null; | |
59 | try { | |
60 | ClassLoader loader = Version.class.getClassLoader(); | |
61 | ||
62 | Properties prop = new Properties(); | |
63 | try { | |
64 | prop.load(loader.getResourceAsStream(RESOURCE_FILENAME)); | |
65 | } catch (IOException e) { | |
66 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version. Cause: Ressource " | |
67 | + RESOURCE_FILENAME + " cannot be read. " + e.getMessage()); | |
68 | } catch (NullPointerException e) { | |
69 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version. Cause: Ressource " | |
70 | + RESOURCE_FILENAME + " not found. " + e.getMessage()); | |
71 | } | |
72 | ||
73 | version = prop.getProperty(VERSION_PROPERTY_NAME); | |
74 | if (version == null) { | |
75 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version: Missing " + VERSION_PROPERTY_NAME + " property."); | |
76 | } else if (version.equals("")) { | |
77 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version: Empty " + VERSION_PROPERTY_NAME + " property."); | |
78 | } else { | |
79 | String[] versions = version.split("\\."); | |
80 | if (version.length() < 3) { | |
81 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version: FULL_VERSION (" + version + ") does not contain 3 components "); | |
82 | } | |
83 | if (versions.length >= 1) { | |
84 | try { | |
85 | major = Integer.parseInt(versions[0]); | |
86 | } catch (NumberFormatException nfe) { | |
87 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version! Error parsing major version "); | |
88 | } | |
89 | } | |
90 | if (versions.length >= 2) { | |
91 | try { | |
92 | minor = Integer.parseInt(versions[1]); | |
93 | } catch (NumberFormatException nfe) { | |
94 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version! Error parsing minor version "); | |
95 | } | |
96 | } | |
97 | if (version.length() >= 3) { | |
98 | micro = versions[2]; | |
99 | } | |
100 | } | |
101 | ||
102 | } finally { | |
103 | MAJOR = major; | |
104 | MINOR = minor; | |
105 | MICRO = micro; | |
106 | VERSION = version; | |
107 | } | |
108 | } | |
109 | ||
110 | /** Full version for human reading - code should use the constants above */ | |
111 | public static final String FULL = "PostGIS JDBC V" + MAJOR + "." + MINOR + "." + MICRO; | |
112 | ||
113 | public static String getFullVersion() { | |
114 | return FULL; | |
115 | } | |
116 | ||
117 | ||
118 | }⏎ |
0 | <body> | |
1 | <p>The JDBC extensions provide Java objects corresponding to the internal PostGIS types. These objects can be used | |
2 | to write Java clients which query the PostGIS database and draw or do calculations on the GIS data in PostGIS. | |
3 | </p> | |
4 | </body>⏎ |
0 | # | |
1 | # This property file is included in the postgis jar and autoregisters the | |
2 | # PostGIS datatypes within the jdbc driver. | |
3 | # | |
4 | ||
5 | datatype.geometry=org.postgis.PGgeometry | |
6 | datatype.geography=org.postgis.PGgeography | |
7 | datatype.box3d=org.postgis.PGbox3d | |
8 | datatype.box2d=org.postgis.PGbox2d |
0 | /* | |
1 | * BoxesTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | ||
30 | import net.postgis.tools.testutils.TestContainerController; | |
31 | import org.postgis.util.VersionUtil; | |
32 | import org.postgresql.util.PGobject; | |
33 | import org.slf4j.Logger; | |
34 | import org.slf4j.LoggerFactory; | |
35 | import org.testng.Assert; | |
36 | import org.testng.ITestContext; | |
37 | import org.testng.annotations.AfterClass; | |
38 | import org.testng.annotations.BeforeClass; | |
39 | import org.testng.annotations.Test; | |
40 | ||
41 | import java.sql.*; | |
42 | ||
43 | ||
44 | public class BoxesTest { | |
45 | ||
46 | private static final Logger logger = LoggerFactory.getLogger(BoxesTest.class); | |
47 | ||
48 | /** Our test candidates: */ | |
49 | public static final String[] BOXEN3D = new String[]{ | |
50 | "BOX3D(1 2 3,4 5 6)", // 3d variant | |
51 | "BOX3D(1 2,4 5)"// 2d variant | |
52 | }; | |
53 | ||
54 | public static final String[] BOXEN2D = new String[]{"BOX(1 2,3 4)"}; | |
55 | ||
56 | private Connection connection = null; | |
57 | ||
58 | ||
59 | @Test | |
60 | public void testBoxes() throws Exception { | |
61 | for (String aBOXEN3D : BOXEN3D) { | |
62 | PGbox3d candidate = new PGbox3d(aBOXEN3D); | |
63 | test(aBOXEN3D, candidate, false); | |
64 | } | |
65 | for (String aBOXEN2D : BOXEN2D) { | |
66 | PGbox2d candidate = new PGbox2d(aBOXEN2D); | |
67 | test(aBOXEN2D, candidate, true); | |
68 | } | |
69 | } | |
70 | ||
71 | ||
72 | public void test(String orig, PGobject candidate, boolean newPostgisOnly) throws Exception { | |
73 | logger.debug("Original: {}", orig); | |
74 | String redone = candidate.toString(); | |
75 | logger.debug("Parsed: {}", redone); | |
76 | Assert.assertEquals(orig, redone, "Recreated Text Rep not equal"); | |
77 | ||
78 | // Simulate the way postgresql-jdbc uses to create PGobjects | |
79 | PGobject recreated = candidate.getClass().newInstance(); | |
80 | recreated.setValue(redone); | |
81 | ||
82 | String reparsed = recreated.toString(); | |
83 | logger.debug("Re-Parsed: " + reparsed); | |
84 | Assert.assertEquals(recreated, candidate, "Recreated boxen are not equal"); | |
85 | Assert.assertEquals(reparsed, orig, "2nd generation text reps are not equal"); | |
86 | ||
87 | logger.debug("testing on connection: {}", connection.getCatalog()); | |
88 | Statement statement = connection.createStatement(); | |
89 | if (newPostgisOnly && Integer.parseInt(VersionUtil.retrievePostGISServerMajorVersion(connection)) < 1) { | |
90 | logger.debug("PostGIS version is too old, not testing box2d"); | |
91 | } else { | |
92 | PGobject sqlGeom = viaSQL(candidate, statement); | |
93 | logger.debug("SQLin : " + sqlGeom.toString()); | |
94 | Assert.assertEquals(candidate, sqlGeom, "Geometries after SQL are not equal"); | |
95 | PGobject sqlreGeom = viaSQL(recreated, statement); | |
96 | logger.debug("SQLout : " + sqlreGeom.toString()); | |
97 | Assert.assertEquals(candidate, sqlreGeom, "reparsed Geometries after SQL are not equal"); | |
98 | } | |
99 | statement.close(); | |
100 | } | |
101 | ||
102 | ||
103 | /** Pass a geometry representation through the SQL server */ | |
104 | private static PGobject viaSQL(PGobject obj, Statement stat) throws SQLException { | |
105 | ResultSet rs = stat.executeQuery("SELECT '" + obj.toString() + "'::" + obj.getType()); | |
106 | rs.next(); | |
107 | return (PGobject) rs.getObject(1); | |
108 | } | |
109 | ||
110 | ||
111 | @BeforeClass | |
112 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
113 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
114 | Assert.assertNotNull(jdbcUrlSuffix); | |
115 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
116 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
117 | Assert.assertNotNull(jdbcUsername); | |
118 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
119 | Assert.assertNotNull(jdbcPassword); | |
120 | Class.forName("org.postgis.DriverWrapper"); | |
121 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
122 | } | |
123 | ||
124 | ||
125 | @AfterClass | |
126 | public void shutdown() throws Exception { | |
127 | logger.debug("shutting down"); | |
128 | if (connection != null) { | |
129 | connection.close(); | |
130 | } | |
131 | } | |
132 | ||
133 | ||
134 | }⏎ |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
16 | * | |
17 | * (C) 2020 Phillip Ross, phillip.w.g.ross@gmail.com | |
18 | */ | |
19 | ||
20 | package org.postgis; | |
21 | ||
22 | ||
23 | import net.postgis.tools.testutils.TestContainerController; | |
24 | import org.postgis.util.VersionUtil; | |
25 | import org.postgresql.Driver; | |
26 | import org.postgresql.util.PGobject; | |
27 | import org.slf4j.Logger; | |
28 | import org.slf4j.LoggerFactory; | |
29 | import org.testng.Assert; | |
30 | import org.testng.ITestContext; | |
31 | import org.testng.annotations.AfterMethod; | |
32 | import org.testng.annotations.BeforeMethod; | |
33 | import org.testng.annotations.Test; | |
34 | ||
35 | import java.sql.Connection; | |
36 | import java.sql.DriverManager; | |
37 | import java.sql.ResultSet; | |
38 | import java.sql.Statement; | |
39 | ||
40 | ||
41 | /** | |
42 | * This test program tests whether the auto-registration of PostGIS data types within the postgresql jdbc driver was | |
43 | * successful. It also checks for PostGIS version to know whether box2d is available. | |
44 | */ | |
45 | public class DatatypesAutoRegistrationTest { | |
46 | ||
47 | /** The static logger instance. */ | |
48 | private static final Logger logger = LoggerFactory.getLogger(DatatypesAutoRegistrationTest.class); | |
49 | ||
50 | /** The JDBC Connection to be used for tests. */ | |
51 | private Connection connection; | |
52 | ||
53 | ||
54 | /** | |
55 | * Initializes a new JDBC Connection. | |
56 | * | |
57 | * @param ctx the test context | |
58 | * @throws Exception when an exception occurs | |
59 | */ | |
60 | @BeforeMethod | |
61 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
62 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
63 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
64 | Assert.assertNotNull(jdbcUrlSuffix); | |
65 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
66 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
67 | Assert.assertNotNull(jdbcUsername); | |
68 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
69 | Assert.assertNotNull(jdbcPassword); | |
70 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
71 | } | |
72 | ||
73 | ||
74 | /** | |
75 | * Un-allocates the JDBC connection. | |
76 | * | |
77 | * @throws Exception when an exception occurs | |
78 | */ | |
79 | @AfterMethod | |
80 | public void shutdown() throws Exception { | |
81 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
82 | logger.debug("shutting down"); | |
83 | if (connection != null) { | |
84 | connection.close(); | |
85 | } | |
86 | } | |
87 | ||
88 | ||
89 | @Test | |
90 | public void testAutoRegistration() throws Exception { | |
91 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
92 | Driver driver = new Driver(); | |
93 | int driverMajorVersion = driver.getMajorVersion(); | |
94 | int driverMinorVersion = driver.getMinorVersion(); | |
95 | logger.debug("Driver version: {}.{}", driverMajorVersion, driverMinorVersion); | |
96 | if (driverMajorVersion < 8) { | |
97 | logger.info( | |
98 | "postgresql driver {}.{} is too old, it does not support auto-registration", | |
99 | driverMajorVersion, driverMinorVersion | |
100 | ); | |
101 | } else { | |
102 | int postgisServerMajor = Integer.parseInt(VersionUtil.retrievePostGISServerMajorVersion(connection)); | |
103 | logger.debug("PostGIS Version: " + postgisServerMajor); | |
104 | Assert.assertNotEquals( | |
105 | postgisServerMajor, | |
106 | 0, | |
107 | "Could not get PostGIS version. Is PostGIS really installed in the database?" | |
108 | ); | |
109 | Statement statement = connection.createStatement(); | |
110 | ||
111 | // Test geometries | |
112 | ResultSet resultSet = statement.executeQuery("SELECT 'POINT(1 2)'::geometry"); | |
113 | resultSet.next(); | |
114 | PGobject result = (PGobject) resultSet.getObject(1); | |
115 | Assert.assertTrue(result instanceof PGgeometry); | |
116 | ||
117 | // Test geography | |
118 | resultSet = statement.executeQuery("SELECT 'POINT(1 2)'::geography"); | |
119 | resultSet.next(); | |
120 | Object geographyRawObject = resultSet.getObject(1); | |
121 | result = (PGobject) resultSet.getObject(1); | |
122 | Assert.assertTrue(result instanceof PGgeography); | |
123 | ||
124 | // Test box3d | |
125 | resultSet = statement.executeQuery("SELECT 'BOX3D(1 2 3, 4 5 6)'::box3d"); | |
126 | resultSet.next(); | |
127 | result = (PGobject) resultSet.getObject(1); | |
128 | Assert.assertTrue(result instanceof PGbox3d); | |
129 | ||
130 | // Test box2d if appropriate | |
131 | if (postgisServerMajor < 1) { | |
132 | logger.info("PostGIS version is too old, skipping box2ed test"); | |
133 | } else { | |
134 | resultSet = statement.executeQuery("SELECT 'BOX(1 2,3 4)'::box2d"); | |
135 | resultSet.next(); | |
136 | result = (PGobject) resultSet.getObject(1); | |
137 | Assert.assertTrue(result instanceof PGbox2d); | |
138 | } | |
139 | } | |
140 | } | |
141 | ||
142 | ||
143 | } |
0 | /* | |
1 | * DatatypesTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | ||
30 | import org.slf4j.Logger; | |
31 | import org.slf4j.LoggerFactory; | |
32 | import org.testng.annotations.Test; | |
33 | ||
34 | import java.sql.SQLException; | |
35 | ||
36 | ||
37 | public class DatatypesTest { | |
38 | ||
39 | private static final Logger logger = LoggerFactory.getLogger(DatatypesTest.class); | |
40 | ||
41 | private static final String mlng_str = "MULTILINESTRING ((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"; | |
42 | ||
43 | ||
44 | @Test | |
45 | public void testPGgeometry() throws SQLException { | |
46 | logger.trace("void testPGgeometry()"); | |
47 | logger.info(mlng_str); | |
48 | PGgeometry pgf = new PGgeometry(mlng_str); | |
49 | logger.info(pgf.toString()); | |
50 | } | |
51 | ||
52 | ||
53 | @Test | |
54 | public void testPGgeography() throws SQLException { | |
55 | logger.trace("void testPGgeography()"); | |
56 | logger.info(mlng_str); | |
57 | PGgeography pgf = new PGgeography(mlng_str); | |
58 | logger.info(pgf.toString()); | |
59 | } | |
60 | ||
61 | ||
62 | }⏎ |
0 | /* | |
1 | * EmptyGeometriesTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | * | |
21 | */ | |
22 | ||
23 | package org.postgis; | |
24 | ||
25 | ||
26 | import net.postgis.tools.testutils.TestContainerController; | |
27 | import org.slf4j.Logger; | |
28 | import org.slf4j.LoggerFactory; | |
29 | import org.testng.Assert; | |
30 | import org.testng.ITestContext; | |
31 | import org.testng.annotations.AfterClass; | |
32 | import org.testng.annotations.BeforeClass; | |
33 | import org.testng.annotations.Test; | |
34 | ||
35 | import java.sql.*; | |
36 | import java.util.ArrayList; | |
37 | import java.util.List; | |
38 | ||
39 | ||
40 | /** | |
41 | * This class contains tests for handling of empty geometries. | |
42 | * | |
43 | * @author Phillip Ross {@literal <phillip.r.g.ross@gmail.com>} | |
44 | */ | |
45 | public class EmptyGeometriesTest { | |
46 | ||
47 | private static final Logger logger = LoggerFactory.getLogger(EmptyGeometriesTest.class); | |
48 | ||
49 | private static final String DRIVER_WRAPPER_CLASS_NAME = "org.postgis.DriverWrapper"; | |
50 | ||
51 | private static final String DRIVER_WRAPPER_AUTOPROBE_CLASS_NAME = "org.postgis.DriverWrapperAutoprobe"; | |
52 | ||
53 | ||
54 | public static final String[] geometriesToTest = new String[] { | |
55 | "POINT", | |
56 | "LINESTRING", | |
57 | "POLYGON", | |
58 | "MULTIPOINT", | |
59 | "MULTILINESTRING", | |
60 | "MULTIPOLYGON", | |
61 | "GEOMETRYCOLLECTION", | |
62 | }; | |
63 | ||
64 | public static final String[] castTypes = new String[] { | |
65 | "bytea", | |
66 | "text", | |
67 | "geometry", | |
68 | "geography" | |
69 | }; | |
70 | ||
71 | private Connection connection = null; | |
72 | ||
73 | private Statement statement = null; | |
74 | ||
75 | ||
76 | @Test | |
77 | public void testSqlStatements() throws SQLException { | |
78 | for (String sqlStatement : generateSqlStatements()) { | |
79 | logger.debug("**********"); | |
80 | logger.debug("* Executing sql statemnent => [{}]", sqlStatement); | |
81 | logger.debug("**********"); | |
82 | try (PreparedStatement preparedStatement = connection.prepareStatement(sqlStatement); | |
83 | ResultSet resultSet = preparedStatement.executeQuery() | |
84 | ) { | |
85 | resultSet.next(); | |
86 | for (int i = 1; i <= castTypes.length; i++) { | |
87 | Object resultSetObject = resultSet.getObject(i); | |
88 | logger.debug("returned resultSetObject {} => (class=[{}]) {}", i, resultSetObject.getClass().getName(), resultSetObject); | |
89 | } | |
90 | resultSet.close(); | |
91 | } | |
92 | } | |
93 | } | |
94 | ||
95 | ||
96 | private List<String> generateSqlStatements() { | |
97 | List<String> sqlStatementList = new ArrayList<>(); | |
98 | for (String geometry : geometriesToTest) { | |
99 | StringBuilder stringBuilder = new StringBuilder("select "); | |
100 | for (String castType : castTypes) { | |
101 | stringBuilder.append("geometry_in('") | |
102 | .append(geometry) | |
103 | .append(" EMPTY')::") | |
104 | .append(castType) | |
105 | .append(", "); | |
106 | } | |
107 | String sqlStatement = stringBuilder.substring(0, stringBuilder.lastIndexOf(",")); | |
108 | logger.debug("generate sql statement: {}", sqlStatement); | |
109 | sqlStatementList.add(sqlStatement); | |
110 | } | |
111 | return sqlStatementList; | |
112 | } | |
113 | ||
114 | ||
115 | @BeforeClass | |
116 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
117 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
118 | Assert.assertNotNull(jdbcUrlSuffix); | |
119 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
120 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
121 | Assert.assertNotNull(jdbcUsername); | |
122 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
123 | Assert.assertNotNull(jdbcPassword); | |
124 | Class.forName(DRIVER_WRAPPER_CLASS_NAME); | |
125 | Class.forName(DRIVER_WRAPPER_AUTOPROBE_CLASS_NAME); | |
126 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
127 | statement = connection.createStatement(); | |
128 | } | |
129 | ||
130 | ||
131 | @AfterClass | |
132 | public void unallocateDatabaseResources() throws Exception { | |
133 | if ((statement != null) && (!statement.isClosed())) { | |
134 | statement.close(); | |
135 | } | |
136 | if ((connection != null) && (!connection.isClosed())) { | |
137 | connection.close(); | |
138 | } | |
139 | } | |
140 | ||
141 | ||
142 | }⏎ |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2020 Phillip Ross, phillip.w.g.ross@gmail.com | |
16 | */ | |
17 | ||
18 | package org.postgis; | |
19 | ||
20 | ||
21 | import net.postgis.tools.testutils.TestContainerController; | |
22 | import org.slf4j.Logger; | |
23 | import org.slf4j.LoggerFactory; | |
24 | import org.testng.Assert; | |
25 | import org.testng.ITestContext; | |
26 | import org.testng.annotations.AfterMethod; | |
27 | import org.testng.annotations.BeforeMethod; | |
28 | import org.testng.annotations.Test; | |
29 | ||
30 | import java.sql.Connection; | |
31 | import java.sql.DatabaseMetaData; | |
32 | import java.sql.DriverManager; | |
33 | import java.sql.PreparedStatement; | |
34 | import java.sql.ResultSet; | |
35 | import java.sql.Statement; | |
36 | import java.util.UUID; | |
37 | ||
38 | ||
39 | /** | |
40 | * Integration tests for PGgeography. | |
41 | * | |
42 | * @author Phillip Ross | |
43 | */ | |
44 | public class GeographyDatatypeTest { | |
45 | ||
46 | /** The static logger instance. */ | |
47 | private static final Logger logger = LoggerFactory.getLogger(GeographyDatatypeTest.class); | |
48 | ||
49 | /** The jdbc url prefix containing the jdbc protocol to be used for tests. */ | |
50 | private static final String JDBC_URL_PROTOCOL_PREFIX = "jdbc:postgresql"; | |
51 | ||
52 | /** The jdbc url prefix containing the jdbc lightweight protocol to be used for tests. */ | |
53 | private static final String JDBC_URL_LW_PROTOCOL_PREFIX = "jdbc:postgresql_lwgis"; | |
54 | ||
55 | /** The prefix for database tables used in the tests. */ | |
56 | private static final String DATABASE_TABLE_NAME_PREFIX = "jdbc_test"; | |
57 | ||
58 | /** Test geometries dataset. */ | |
59 | public static final String[] testGeometries = new String[] { | |
60 | "POINT(10 10)", // 2D | |
61 | "POINT(10 10 0)", // 3D with 3rd coordinate set to 0 | |
62 | "POINT(10 10 20)", // 3D | |
63 | "POINT(1e100 1.2345e-100 -2e-5)", // 3D with scientific notation | |
64 | "POINTM(10 10 20)", // 2D + Measures | |
65 | "POINT(10 10 20 30)", // 3D + Measures | |
66 | "MULTIPOINT(11 12, 20 20)", // broken format, see http://lists.jump-project.org/pipermail/jts-devel/2006-April/001572.html | |
67 | "MULTIPOINT(11 12 13, 20 20 20)", // broken format | |
68 | "MULTIPOINTM(11 12 13, 20 20 20)", // broken format | |
69 | "MULTIPOINT(11 12 13 14,20 20 20 20)", // broken format | |
70 | "MULTIPOINT((11 12), (20 20))", // OGC conforming format | |
71 | "MULTIPOINT((11 12 13), (20 20 20))", | |
72 | "MULTIPOINTM((11 12 13), (20 20 20))", | |
73 | "MULTIPOINT((11 12 13 14),(20 20 20 20))", | |
74 | "LINESTRING(10 10,20 20,50 50,34 34)", | |
75 | "LINESTRING(10 10 20,20 20 20,50 50 50,34 34 34)", | |
76 | "LINESTRINGM(10 10 20,20 20 20,50 50 50,34 34 34)", | |
77 | "LINESTRING(10 10 20 20,20 20 20 20,50 50 50 50,34 34 34 50)", | |
78 | "POLYGON((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))", | |
79 | "POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", | |
80 | "POLYGONM((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", | |
81 | "POLYGON((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7))", | |
82 | "MULTIPOLYGON(((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)),((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)))", | |
83 | "MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", | |
84 | "MULTIPOLYGONM(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", | |
85 | "MULTIPOLYGON(((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7)),((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7)))", | |
86 | "MULTILINESTRING((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))", | |
87 | "MULTILINESTRING((10 10 5,20 10 5,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", | |
88 | "MULTILINESTRINGM((10 10 7,20 10 7,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", | |
89 | "MULTILINESTRING((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7))", | |
90 | "GEOMETRYCOLLECTION(POINT(10 10),POINT(20 20))", | |
91 | "GEOMETRYCOLLECTION(POINT(10 10 20),POINT(20 20 20))", | |
92 | "GEOMETRYCOLLECTION(POINT(10 10 20 7),POINT(20 20 20 7))", | |
93 | "GEOMETRYCOLLECTION(LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34))", | |
94 | "GEOMETRYCOLLECTION(POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", | |
95 | "GEOMETRYCOLLECTION(MULTIPOINT(10 10 10, 20 20 20),MULTIPOINT(10 10 10, 20 20 20))", // Cannot be parsed by 0.X servers, broken format | |
96 | "GEOMETRYCOLLECTION(MULTIPOINT((10 10 10), (20 20 20)),MULTIPOINT((10 10 10), (20 20 20)))", // Cannot be parsed by 0.X servers, OGC conformant | |
97 | "GEOMETRYCOLLECTION(MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", // PostGIs 0.X "flattens" this geometry, so it is not equal after reparsing. | |
98 | "GEOMETRYCOLLECTION(MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))))", // PostGIs 0.X "flattens" this geometry, so it is not equal after reparsing. | |
99 | "GEOMETRYCOLLECTION(POINT(10 10 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", | |
100 | "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT(10 10 10, 20 20 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", // Collections that contain both X and MultiX do not work on PostGIS 0.x, broken format | |
101 | "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT((10 10 10), (20 20 20)),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", // Collections that contain both X and MultiX do not work on PostGIS 0.x, OGC conformant | |
102 | "GEOMETRYCOLLECTION EMPTY", // new (correct) representation | |
103 | "GEOMETRYCOLLECTIONM(POINTM(10 10 20),POINTM(20 20 20))" | |
104 | }; | |
105 | ||
106 | /** The JDBC Connection to be used for tests. */ | |
107 | private Connection connection = null; | |
108 | ||
109 | /** The JDBC Connection w/ lightweight protocol to be used for tests. */ | |
110 | private Connection connectionLW = null; | |
111 | ||
112 | ||
113 | /** | |
114 | * Initializes a new JDBC Connection. | |
115 | * | |
116 | * @param ctx the test context | |
117 | * @throws Exception when an exception occurs | |
118 | */ | |
119 | @BeforeMethod | |
120 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
121 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
122 | Assert.assertNotNull(jdbcUrlSuffix); | |
123 | final String jdbcUrl = JDBC_URL_PROTOCOL_PREFIX + jdbcUrlSuffix; | |
124 | final String jdbcUrlLW = JDBC_URL_LW_PROTOCOL_PREFIX + jdbcUrlSuffix; | |
125 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
126 | Assert.assertNotNull(jdbcUsername); | |
127 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
128 | Assert.assertNotNull(jdbcPassword); | |
129 | Class.forName("org.postgis.DriverWrapperLW"); | |
130 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
131 | connectionLW = DriverManager.getConnection(jdbcUrlLW, jdbcUsername, jdbcPassword); | |
132 | } | |
133 | ||
134 | ||
135 | /** | |
136 | * Un-allocates the JDBC connection. | |
137 | * | |
138 | * @throws Exception when an exception occurs | |
139 | */ | |
140 | @AfterMethod | |
141 | public void unallocateDatabaseResources() throws Exception { | |
142 | if ((connection != null) && (!connection.isClosed())) { | |
143 | connection.close(); | |
144 | } | |
145 | if ((connectionLW != null) && (!connectionLW.isClosed())) { | |
146 | connection.close(); | |
147 | } | |
148 | } | |
149 | ||
150 | ||
151 | /** | |
152 | * Test inserting geometries into the database with prepared statements and querying back the results with | |
153 | * both geometry/geography and standard/lightweight. | |
154 | * | |
155 | * @throws Exception when an exception occurs. | |
156 | */ | |
157 | @Test | |
158 | public void testDatatypes() throws Exception { | |
159 | ||
160 | final String testTableName = DATABASE_TABLE_NAME_PREFIX | |
161 | + "_" | |
162 | + UUID.randomUUID() | |
163 | .toString() | |
164 | .replaceAll("-", ""); | |
165 | ||
166 | final String dropTableSQL = "drop table " + testTableName; | |
167 | ||
168 | final String createTableSQL = "create table " + testTableName | |
169 | + " ( _id numeric," | |
170 | + " geometry_value geometry, geometrylw_value geometry," | |
171 | + " geography_value geography, geographylw_value geography)"; | |
172 | final int idColumnIndex = 1; | |
173 | final int geometryValueColumnIndex = 2; | |
174 | final int geometrylwValueColumnIndex = 3; | |
175 | final int geographyValueColumnIndex = 4; | |
176 | final int geographylwValueColumnIndex = 5; | |
177 | ||
178 | final String insertSQL = "insert into " + testTableName + " ( " | |
179 | + "_id, geometry_value, geometrylw_value, " | |
180 | + "geography_value, geographylw_value) " | |
181 | + "values ( ?, ?, ?, ?, ? )"; | |
182 | ||
183 | boolean tableExists = false; | |
184 | DatabaseMetaData databaseMetaData = connection.getMetaData(); | |
185 | try ( | |
186 | ResultSet resultSet = databaseMetaData.getTables( | |
187 | null, null, testTableName.toLowerCase(), new String[] { "TABLE" } | |
188 | ) | |
189 | ) { | |
190 | while (resultSet.next()) { | |
191 | tableExists = true; | |
192 | } | |
193 | } | |
194 | ||
195 | if (tableExists) { | |
196 | logger.debug("Dropping pre-existing test table..."); | |
197 | try (Statement statement = connection.createStatement()) { | |
198 | statement.executeQuery(dropTableSQL); | |
199 | } | |
200 | } | |
201 | ||
202 | logger.debug("Creating test table..."); | |
203 | try (Statement statement = connection.createStatement()) { | |
204 | statement.execute(createTableSQL); | |
205 | } | |
206 | ||
207 | ||
208 | logger.debug("Inserting test geometries into table..."); | |
209 | try (PreparedStatement preparedStatement = connection.prepareStatement(insertSQL)) { | |
210 | for (int i = 0; i < testGeometries.length; i++) { | |
211 | PGgeometry geometry = new PGgeometry(testGeometries[i]); | |
212 | PGgeometryLW geometryLW = new PGgeometryLW(testGeometries[i]); | |
213 | PGgeography geography = new PGgeography(testGeometries[i]); | |
214 | PGgeographyLW geographyLW = new PGgeographyLW(testGeometries[i]); | |
215 | ||
216 | preparedStatement.setInt(idColumnIndex, i); | |
217 | preparedStatement.setObject(geometryValueColumnIndex, geometry); | |
218 | preparedStatement.setObject(geometrylwValueColumnIndex, geometryLW); | |
219 | preparedStatement.setObject(geographyValueColumnIndex, geography); | |
220 | preparedStatement.setObject(geographylwValueColumnIndex, geographyLW); | |
221 | preparedStatement.executeUpdate(); | |
222 | } | |
223 | } | |
224 | ||
225 | logger.debug("Querying table with standard connection..."); | |
226 | try ( | |
227 | Statement statement = connection.createStatement(); | |
228 | ResultSet resultSet = statement.executeQuery( | |
229 | "select _id, geometry_value, geometrylw_value, geography_value, geographylw_value from " | |
230 | + testTableName | |
231 | ) | |
232 | ) { | |
233 | while (resultSet.next()) { | |
234 | Assert.assertEquals(resultSet.getObject(geometryValueColumnIndex).getClass(), PGgeometry.class); | |
235 | Assert.assertEquals(resultSet.getObject(geometrylwValueColumnIndex).getClass(), PGgeometry.class); | |
236 | Assert.assertEquals(resultSet.getObject(geographyValueColumnIndex).getClass(), PGgeography.class); | |
237 | Assert.assertEquals(resultSet.getObject(geographylwValueColumnIndex).getClass(), PGgeography.class); | |
238 | } | |
239 | } | |
240 | ||
241 | logger.debug("Querying table with lightweight connection..."); | |
242 | try ( | |
243 | Statement statement = connectionLW.createStatement(); | |
244 | ResultSet resultSet = statement.executeQuery( | |
245 | "select _id, geometry_value, geometrylw_value, geography_value, geographylw_value from " | |
246 | + testTableName | |
247 | ) | |
248 | ) { | |
249 | while (resultSet.next()) { | |
250 | Assert.assertEquals(resultSet.getObject(geometryValueColumnIndex).getClass(), PGgeometryLW.class); | |
251 | Assert.assertEquals(resultSet.getObject(geometrylwValueColumnIndex).getClass(), PGgeometryLW.class); | |
252 | Assert.assertEquals(resultSet.getObject(geographyValueColumnIndex).getClass(), PGgeographyLW.class); | |
253 | Assert.assertEquals(resultSet.getObject(geographylwValueColumnIndex).getClass(), PGgeographyLW.class); | |
254 | } | |
255 | } | |
256 | } | |
257 | ||
258 | ||
259 | }⏎ |
0 | /* | |
1 | * ParserTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | ||
30 | import org.postgis.binary.BinaryParser; | |
31 | import org.postgis.binary.BinaryWriter; | |
32 | import org.postgis.binary.ValueSetter; | |
33 | import net.postgis.tools.testutils.TestContainerController; | |
34 | import org.postgis.util.VersionUtil; | |
35 | import org.slf4j.Logger; | |
36 | import org.slf4j.LoggerFactory; | |
37 | import org.testng.Assert; | |
38 | import org.testng.ITestContext; | |
39 | import org.testng.annotations.AfterClass; | |
40 | import org.testng.annotations.BeforeClass; | |
41 | import org.testng.annotations.Test; | |
42 | ||
43 | import java.sql.Connection; | |
44 | import java.sql.DriverManager; | |
45 | import java.sql.PreparedStatement; | |
46 | import java.sql.ResultSet; | |
47 | import java.sql.SQLException; | |
48 | import java.sql.Statement; | |
49 | import java.sql.Types; | |
50 | import java.util.Objects; | |
51 | ||
52 | ||
53 | public class ParserTest { | |
54 | ||
55 | private static final Logger logger = LoggerFactory.getLogger(ParserTest.class); | |
56 | ||
57 | private static final String DRIVER_WRAPPER_CLASS_NAME = "org.postgis.DriverWrapper"; | |
58 | ||
59 | private static final String DRIVER_WRAPPER_AUTOPROBE_CLASS_NAME = "org.postgis.DriverWrapperAutoprobe"; | |
60 | ||
61 | /** The srid we use for the srid tests */ | |
62 | public static final int SRID = 4326; | |
63 | ||
64 | /** The string prefix we get for the srid tests */ | |
65 | public static final String SRIDPREFIX = "SRID=" + SRID + ";"; | |
66 | ||
67 | /** | |
68 | * Our set of geometries to test. | |
69 | */ | |
70 | public static final String ALL = "ALL"; | |
71 | public static final String ONLY10 = "ONLY10"; | |
72 | public static final String EQUAL10 = "EQUAL10"; | |
73 | public static final String[][] testset = new String[][]{ | |
74 | { | |
75 | ALL, // 2D | |
76 | "POINT(10 10)"}, | |
77 | { | |
78 | ALL, // 3D with 3rd coordinate set to 0 | |
79 | "POINT(10 10 0)"}, | |
80 | { | |
81 | ALL, // 3D | |
82 | "POINT(10 10 20)"}, | |
83 | { | |
84 | ALL, // 3D with scientific notation | |
85 | "POINT(1e100 1.2345e-100 -2e-5)"}, | |
86 | { | |
87 | ONLY10, // 2D + Measures | |
88 | "POINTM(10 10 20)"}, | |
89 | { | |
90 | ONLY10, // 3D + Measures | |
91 | "POINT(10 10 20 30)"}, | |
92 | { | |
93 | ALL, // broken format, see http://lists.jump-project.org/pipermail/jts-devel/2006-April/001572.html | |
94 | "MULTIPOINT(11 12, 20 20)"}, | |
95 | { | |
96 | ALL,// broken format | |
97 | "MULTIPOINT(11 12 13, 20 20 20)"}, | |
98 | { | |
99 | ONLY10,// broken format | |
100 | "MULTIPOINTM(11 12 13, 20 20 20)"}, | |
101 | { | |
102 | ONLY10,// broken format | |
103 | "MULTIPOINT(11 12 13 14,20 20 20 20)"}, | |
104 | { | |
105 | ALL, // OGC conforming format | |
106 | "MULTIPOINT((11 12), (20 20))"}, | |
107 | { | |
108 | ALL, | |
109 | "MULTIPOINT((11 12 13), (20 20 20))"}, | |
110 | { | |
111 | ONLY10, | |
112 | "MULTIPOINTM((11 12 13), (20 20 20))"}, | |
113 | { | |
114 | ONLY10, | |
115 | "MULTIPOINT((11 12 13 14),(20 20 20 20))"}, | |
116 | { | |
117 | ALL, | |
118 | "LINESTRING(10 10,20 20,50 50,34 34)"}, | |
119 | { | |
120 | ALL, | |
121 | "LINESTRING(10 10 20,20 20 20,50 50 50,34 34 34)"}, | |
122 | { | |
123 | ONLY10, | |
124 | "LINESTRINGM(10 10 20,20 20 20,50 50 50,34 34 34)"}, | |
125 | { | |
126 | ONLY10, | |
127 | "LINESTRING(10 10 20 20,20 20 20 20,50 50 50 50,34 34 34 50)"}, | |
128 | { | |
129 | ALL, | |
130 | "POLYGON((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))"}, | |
131 | { | |
132 | ALL, | |
133 | "POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"}, | |
134 | { | |
135 | ONLY10, | |
136 | "POLYGONM((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"}, | |
137 | { | |
138 | ONLY10, | |
139 | "POLYGON((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7))"}, | |
140 | { | |
141 | ALL, | |
142 | "MULTIPOLYGON(((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)),((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)))"}, | |
143 | { | |
144 | ALL, | |
145 | "MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
146 | { | |
147 | ONLY10, | |
148 | "MULTIPOLYGONM(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
149 | { | |
150 | ONLY10, | |
151 | "MULTIPOLYGON(((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7)),((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7)))"}, | |
152 | { | |
153 | ALL, | |
154 | "MULTILINESTRING((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))"}, | |
155 | { | |
156 | ALL, | |
157 | "MULTILINESTRING((10 10 5,20 10 5,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"}, | |
158 | { | |
159 | ONLY10, | |
160 | "MULTILINESTRINGM((10 10 7,20 10 7,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"}, | |
161 | { | |
162 | ONLY10, | |
163 | "MULTILINESTRING((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7))"}, | |
164 | { | |
165 | ALL, | |
166 | "GEOMETRYCOLLECTION(POINT(10 10),POINT(20 20))"}, | |
167 | { | |
168 | ALL, | |
169 | "GEOMETRYCOLLECTION(POINT(10 10 20),POINT(20 20 20))"}, | |
170 | { | |
171 | ONLY10, | |
172 | "GEOMETRYCOLLECTION(POINT(10 10 20 7),POINT(20 20 20 7))"}, | |
173 | { | |
174 | ALL, | |
175 | "GEOMETRYCOLLECTION(LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34))"}, | |
176 | { | |
177 | ALL, | |
178 | "GEOMETRYCOLLECTION(POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
179 | { | |
180 | ONLY10, // Cannot be parsed by 0.X servers, broken format | |
181 | "GEOMETRYCOLLECTION(MULTIPOINT(10 10 10, 20 20 20),MULTIPOINT(10 10 10, 20 20 20))"}, | |
182 | { | |
183 | ONLY10, // Cannot be parsed by 0.X servers, OGC conformant | |
184 | "GEOMETRYCOLLECTION(MULTIPOINT((10 10 10), (20 20 20)),MULTIPOINT((10 10 10), (20 20 20)))"}, | |
185 | { | |
186 | EQUAL10, // PostGIs 0.X "flattens" this geometry, so it is not | |
187 | // equal after reparsing. | |
188 | "GEOMETRYCOLLECTION(MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
189 | { | |
190 | EQUAL10,// PostGIs 0.X "flattens" this geometry, so it is not equal | |
191 | // after reparsing. | |
192 | "GEOMETRYCOLLECTION(MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))))"}, | |
193 | { | |
194 | ALL, | |
195 | "GEOMETRYCOLLECTION(POINT(10 10 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
196 | { | |
197 | ONLY10, // Collections that contain both X and MultiX do not work on | |
198 | // PostGIS 0.x, broken format | |
199 | "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT(10 10 10, 20 20 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
200 | { | |
201 | ONLY10, // Collections that contain both X and MultiX do not work on | |
202 | // PostGIS 0.x, OGC conformant | |
203 | "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT((10 10 10), (20 20 20)),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
204 | { | |
205 | ALL,// new (correct) representation | |
206 | "GEOMETRYCOLLECTION EMPTY"}, | |
207 | { | |
208 | ALL, | |
209 | "GEOMETRYCOLLECTIONM(POINTM(10 10 20),POINTM(20 20 20))"}, | |
210 | // end | |
211 | }; | |
212 | ||
213 | public static final String[][] testSetNonWorking = new String[][]{ | |
214 | { | |
215 | ALL, // Old (bad) PostGIS 0.X Representation | |
216 | "GEOMETRYCOLLECTION(EMPTY)"}, | |
217 | { | |
218 | ONLY10,// new (correct) representation - does not work on 0.X | |
219 | "POINT EMPTY"}, | |
220 | { | |
221 | ONLY10,// new (correct) representation - does not work on 0.X | |
222 | "LINESTRING EMPTY"}, | |
223 | { | |
224 | ONLY10,// new (correct) representation - does not work on 0.X | |
225 | "POLYGON EMPTY"}, | |
226 | { | |
227 | ONLY10,// new (correct) representation - does not work on 0.X | |
228 | "MULTIPOINT EMPTY"}, | |
229 | { | |
230 | ONLY10,// new (correct) representation - does not work on 0.X | |
231 | "MULTILINESTRING EMPTY"}, | |
232 | { | |
233 | ONLY10,// new (correct) representation - does not work on 0.X | |
234 | "MULTIPOLYGON EMPTY"} | |
235 | }; | |
236 | ||
237 | private static BinaryParser binaryParser = new BinaryParser(); | |
238 | ||
239 | private static final BinaryWriter binaryWriter = new BinaryWriter(); | |
240 | ||
241 | private Connection connection = null; | |
242 | ||
243 | private Statement statement = null; | |
244 | ||
245 | ||
246 | @Test | |
247 | public void testParser() throws Exception { | |
248 | for (String[] aTestset : testset) { | |
249 | test(aTestset[1], aTestset[0]); | |
250 | test(SRIDPREFIX + aTestset[1], aTestset[0]); | |
251 | } | |
252 | } | |
253 | ||
254 | ||
255 | public void test(String WKT, String flags) throws SQLException { | |
256 | logger.debug("Original: {} ", WKT); | |
257 | Geometry geom = GeometryBuilder.geomFromString(WKT); | |
258 | String parsed = geom.toString(); | |
259 | logger.debug("Parsed: {}", parsed); | |
260 | Geometry regeom = GeometryBuilder.geomFromString(parsed); | |
261 | String reparsed = regeom.toString(); | |
262 | logger.debug("Re-Parsed: {}", reparsed); | |
263 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
264 | Assert.assertEquals(reparsed, parsed, "Text Reps are not equal"); | |
265 | ||
266 | String hexNWKT = binaryWriter.writeHexed(regeom, ValueSetter.NDR.NUMBER); | |
267 | logger.debug("NDRHex: {}", hexNWKT); | |
268 | regeom = GeometryBuilder.geomFromString(hexNWKT); | |
269 | logger.debug("ReNDRHex: {}", regeom); | |
270 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
271 | ||
272 | String hexXWKT = binaryWriter.writeHexed(regeom, ValueSetter.XDR.NUMBER); | |
273 | logger.debug("XDRHex: {}", hexXWKT); | |
274 | regeom = GeometryBuilder.geomFromString(hexXWKT); | |
275 | logger.debug("ReXDRHex: {}", regeom); | |
276 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
277 | ||
278 | byte[] NWKT = binaryWriter.writeBinary(regeom, ValueSetter.NDR.NUMBER); | |
279 | regeom = binaryParser.parse(NWKT); | |
280 | logger.debug("NDR: {}", regeom); | |
281 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
282 | ||
283 | byte[] XWKT = binaryWriter.writeBinary(regeom, ValueSetter.XDR.NUMBER); | |
284 | regeom = binaryParser.parse(XWKT); | |
285 | logger.debug("XDR: {}", regeom); | |
286 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
287 | ||
288 | final String postGISVersionString = VersionUtil.retrievePostGISServerVersionString(connection); | |
289 | logger.debug("postGISVersionString: {}", postGISVersionString); | |
290 | final String postGISMajorVersion = VersionUtil.retrievePostGISServerMajorVersion(connection); | |
291 | logger.debug("postGISMajorVersion: {}", postGISMajorVersion); | |
292 | final String postGISMinorVersion = VersionUtil.retrievePostGISServerMinorVersion(connection); | |
293 | logger.debug("postGISMinorVersion: {}", postGISMinorVersion); | |
294 | ||
295 | int serverPostgisMajor = 0; | |
296 | try { | |
297 | serverPostgisMajor = Integer.parseInt(postGISMajorVersion); | |
298 | } catch (NumberFormatException nfe) { | |
299 | logger.error("Caught a number format exception attempting to parse PostGIS Server Major Version"); | |
300 | } | |
301 | ||
302 | if ((Objects.equals(flags, ONLY10)) && serverPostgisMajor < 1) { | |
303 | logger.info("PostGIS server too old, skipping test on database connection {}", connection.getCatalog()); | |
304 | } else { | |
305 | logger.debug("Testing on connection {}", connection.getCatalog()); | |
306 | ||
307 | Geometry sqlGeom = viaSQL(WKT); | |
308 | logger.debug("SQLin: {}", sqlGeom); | |
309 | if (!geom.equals(sqlGeom)) { | |
310 | logger.warn("Geometries after SQL are not equal"); | |
311 | if (Objects.equals(flags, EQUAL10) && serverPostgisMajor < 1) { | |
312 | logger.info("This is expected with PostGIS {}.X", serverPostgisMajor); | |
313 | } else { | |
314 | Assert.fail(); | |
315 | } | |
316 | } | |
317 | ||
318 | Geometry sqlreGeom = viaSQL(parsed); | |
319 | logger.debug("SQLout: {}", sqlreGeom); | |
320 | if (!geom.equals(sqlreGeom)) { | |
321 | logger.warn("Reparsed Geometries after SQL are not equal!"); | |
322 | if (Objects.equals(flags, EQUAL10) && serverPostgisMajor < 1) { | |
323 | logger.info("This is expected with PostGIS {}.X", serverPostgisMajor); | |
324 | } else { | |
325 | Assert.fail(); | |
326 | } | |
327 | } | |
328 | ||
329 | sqlreGeom = viaPrepSQL(geom, connection); | |
330 | logger.debug("Prepared: {}", sqlreGeom.toString()); | |
331 | if (!geom.equals(sqlreGeom)) { | |
332 | logger.warn("Reparsed Geometries after prepared StatementSQL are not equal!"); | |
333 | if (Objects.equals(flags, EQUAL10) && serverPostgisMajor < 1) { | |
334 | logger.info("This is expected with PostGIS {}.X", serverPostgisMajor); | |
335 | } else { | |
336 | Assert.fail(); | |
337 | } | |
338 | } | |
339 | ||
340 | /* | |
341 | // Temporarily removing this check since it breaks between PostGIS v2.4.4 and PostGIS v2.5.0 | |
342 | // Tests performed via psql between mdillon/postgis:9.3 and mdillon/postgis:9.4 shows the breakage | |
343 | // Test is also broken in mdillon/postgis:11-alpine | |
344 | // In psql, the sql statement "SELECT ST_AsEWKT(geometry_in('POINT(1e100 1.2345e-100 -2e-5)'));" returns | |
345 | // "POINT(1e+100 1.2345e-100 -2e-05)" with 9.3 and "POINT(1e+100 0 -0.00002)" with 9.4 and later | |
346 | ||
347 | // asEWKT() function is not present on PostGIS 0.X, and the test | |
348 | // is pointless as 0.X uses EWKT as canonical rep so the same | |
349 | // functionality was already tested above. | |
350 | if (serverPostgisMajor >= 1) { | |
351 | sqlGeom = ewktViaSQL(WKT, statement); | |
352 | logger.debug("asEWKT: {}", sqlGeom); | |
353 | Assert.assertEquals(geom, sqlGeom); | |
354 | } | |
355 | */ | |
356 | ||
357 | // asEWKB() function is not present on PostGIS 0.X. | |
358 | if (serverPostgisMajor >= 1) { | |
359 | sqlGeom = ewkbViaSQL(WKT, statement); | |
360 | logger.debug("asEWKB: {}", sqlGeom); | |
361 | Assert.assertEquals(geom, sqlGeom); | |
362 | } | |
363 | ||
364 | // HexEWKB parsing is not present on PostGIS 0.X. | |
365 | if (serverPostgisMajor >= 1) { | |
366 | sqlGeom = viaSQL(hexNWKT); | |
367 | logger.debug("hexNWKT: {}", sqlGeom); | |
368 | Assert.assertEquals(geom, sqlGeom); | |
369 | } | |
370 | ||
371 | if (serverPostgisMajor >= 1) { | |
372 | sqlGeom = viaSQL(hexXWKT); | |
373 | logger.debug("hexXWKT: {}", sqlGeom); | |
374 | Assert.assertEquals(geom, sqlGeom); | |
375 | } | |
376 | ||
377 | // Canonical binary input is not present before 1.0 | |
378 | if (serverPostgisMajor >= 1) { | |
379 | sqlGeom = binaryViaSQL(NWKT, connection); | |
380 | logger.debug("NWKT: {}", sqlGeom); | |
381 | Assert.assertEquals(geom, sqlGeom); | |
382 | } | |
383 | ||
384 | if (serverPostgisMajor >= 1) { | |
385 | sqlGeom = binaryViaSQL(XWKT, connection); | |
386 | logger.debug("XWKT: {}", sqlGeom); | |
387 | Assert.assertEquals(geom, sqlGeom); | |
388 | } | |
389 | } | |
390 | } | |
391 | ||
392 | ||
393 | /** Pass a geometry representation through the SQL server */ | |
394 | private Geometry viaSQL(String rep) throws SQLException { | |
395 | logger.trace("Geometry viaSQL(String rep)"); | |
396 | logger.trace("[P] rep => {}", rep); | |
397 | ResultSet resultSet = statement.executeQuery("SELECT geometry_in('" + rep + "')"); | |
398 | resultSet.next(); | |
399 | return ((PGgeometry) resultSet.getObject(1)).getGeometry(); | |
400 | } | |
401 | ||
402 | ||
403 | /** | |
404 | * Pass a geometry representation through the SQL server via prepared | |
405 | * statement | |
406 | */ | |
407 | private static Geometry viaPrepSQL(Geometry geom, Connection conn) throws SQLException { | |
408 | PreparedStatement preparedStatement = conn.prepareStatement("SELECT ?::geometry"); | |
409 | PGgeometry wrapper = new PGgeometry(geom); | |
410 | preparedStatement.setObject(1, wrapper, Types.OTHER); | |
411 | ResultSet resultSet = preparedStatement.executeQuery(); | |
412 | resultSet.next(); | |
413 | PGgeometry resultwrapper = (PGgeometry)resultSet.getObject(1); | |
414 | return resultwrapper.getGeometry(); | |
415 | } | |
416 | ||
417 | ||
418 | /** Pass a geometry representation through the SQL server via EWKT */ | |
419 | private static Geometry ewktViaSQL(String rep, Statement stat) throws SQLException { | |
420 | ResultSet resultSet = stat.executeQuery("SELECT ST_AsEWKT(geometry_in('" + rep + "'))"); | |
421 | resultSet.next(); | |
422 | String resrep = resultSet.getString(1); | |
423 | return GeometryBuilder.geomFromString(resrep); | |
424 | } | |
425 | ||
426 | ||
427 | /** Pass a geometry representation through the SQL server via EWKB */ | |
428 | private static Geometry ewkbViaSQL(String rep, Statement stat) throws SQLException { | |
429 | ResultSet resultSet = stat.executeQuery("SELECT ST_AsEWKB(geometry_in('" + rep + "'))"); | |
430 | resultSet.next(); | |
431 | byte[] resrep = resultSet.getBytes(1); | |
432 | return binaryParser.parse(resrep); | |
433 | } | |
434 | ||
435 | ||
436 | /** Pass a EWKB geometry representation through the server */ | |
437 | private static Geometry binaryViaSQL(byte[] rep, Connection conn) throws SQLException { | |
438 | PreparedStatement preparedStatement = conn.prepareStatement("SELECT ?::bytea::geometry"); | |
439 | preparedStatement.setBytes(1, rep); | |
440 | ResultSet resultSet = preparedStatement.executeQuery(); | |
441 | resultSet.next(); | |
442 | PGgeometry resultwrapper = ((PGgeometry) resultSet.getObject(1)); | |
443 | return resultwrapper.getGeometry(); | |
444 | } | |
445 | ||
446 | ||
447 | @BeforeClass | |
448 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
449 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
450 | Assert.assertNotNull(jdbcUrlSuffix); | |
451 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
452 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
453 | Assert.assertNotNull(jdbcUsername); | |
454 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
455 | Assert.assertNotNull(jdbcPassword); | |
456 | Class.forName(DRIVER_WRAPPER_CLASS_NAME); | |
457 | Class.forName(DRIVER_WRAPPER_AUTOPROBE_CLASS_NAME); | |
458 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
459 | statement = connection.createStatement(); | |
460 | } | |
461 | ||
462 | ||
463 | @AfterClass | |
464 | public void unallocateDatabaseResources() throws Exception { | |
465 | if ((statement != null) && (!statement.isClosed())) { | |
466 | statement.close(); | |
467 | } | |
468 | if ((connection != null) && (!connection.isClosed())) { | |
469 | connection.close(); | |
470 | } | |
471 | } | |
472 | ||
473 | ||
474 | }⏎ |
0 | /* | |
1 | * ServerTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2017 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | ||
30 | import org.testng.Assert; | |
31 | import org.testng.annotations.Test; | |
32 | ||
33 | import java.io.ByteArrayOutputStream; | |
34 | import java.io.NotSerializableException; | |
35 | import java.io.ObjectOutputStream; | |
36 | ||
37 | ||
38 | public class SerializationTest { | |
39 | ||
40 | ||
41 | @Test | |
42 | public void serializationCheckPGgeometry() throws Exception { | |
43 | try { | |
44 | new ObjectOutputStream(new ByteArrayOutputStream()) | |
45 | .writeObject(new PGgeometry("MULTIPOLYGON(((1 1,1 2,2 1,1 1)))")); | |
46 | } | |
47 | catch (NotSerializableException ex) { | |
48 | Assert.fail("serialization of PGgeometry failed: " + ex); | |
49 | } | |
50 | } | |
51 | ||
52 | ||
53 | } |
0 | /* | |
1 | * ServerTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | ||
30 | import net.postgis.tools.testutils.TestContainerController; | |
31 | import org.slf4j.Logger; | |
32 | import org.slf4j.LoggerFactory; | |
33 | import org.testng.Assert; | |
34 | import org.testng.ITestContext; | |
35 | import org.testng.annotations.AfterClass; | |
36 | import org.testng.annotations.BeforeClass; | |
37 | import org.testng.annotations.Test; | |
38 | ||
39 | import java.sql.*; | |
40 | import java.util.UUID; | |
41 | ||
42 | ||
43 | public class ServerTest { | |
44 | ||
45 | private static final Logger logger = LoggerFactory.getLogger(ServerTest.class); | |
46 | ||
47 | private static final String JDBC_DRIVER_CLASS_NAME = "org.postgresql.Driver"; | |
48 | ||
49 | private static final String DATABASE_TABLE_NAME_PREFIX = "jdbc_test"; | |
50 | ||
51 | private Connection connection = null; | |
52 | ||
53 | private Statement statement = null; | |
54 | ||
55 | ||
56 | @Test | |
57 | public void testServer() throws Exception { | |
58 | String dbtable = DATABASE_TABLE_NAME_PREFIX + "_" + UUID.randomUUID().toString().replaceAll("-", ""); | |
59 | ||
60 | String dropSQL = "drop table " + dbtable; | |
61 | String createSQL = "create table " + dbtable + " (geom geometry, id int4)"; | |
62 | String insertPointSQL = "insert into " + dbtable + " values ('POINT (10 10 10)',1)"; | |
63 | String insertPolygonSQL = "insert into " + dbtable + " values ('POLYGON ((0 0 0,0 10 0,10 10 0,10 0 0,0 0 0))',2)"; | |
64 | ||
65 | logger.debug("Adding geometric type entries..."); | |
66 | ((org.postgresql.PGConnection)connection).addDataType("geometry", PGgeometry.class); | |
67 | ((org.postgresql.PGConnection)connection).addDataType("box3d", PGbox3d.class); | |
68 | ||
69 | logger.debug("Creating table with geometric types..."); | |
70 | boolean tableExists = false; | |
71 | DatabaseMetaData databaseMetaData = connection.getMetaData(); | |
72 | try (ResultSet resultSet = databaseMetaData.getTables(null, null, dbtable.toLowerCase(), new String[] {"TABLE"})) { | |
73 | while (resultSet.next()) { | |
74 | tableExists = true; | |
75 | } | |
76 | } | |
77 | if (tableExists) { | |
78 | statement.execute(dropSQL); | |
79 | } | |
80 | statement.execute(createSQL); | |
81 | ||
82 | logger.debug("Inserting point..."); | |
83 | statement.execute(insertPointSQL); | |
84 | ||
85 | logger.debug("Inserting polygon..."); | |
86 | statement.execute(insertPolygonSQL); | |
87 | ||
88 | logger.debug("Querying table..."); | |
89 | ResultSet resultSet = statement.executeQuery("select ST_AsText(geom),id from " + dbtable); | |
90 | while (resultSet.next()) { | |
91 | Object obj = resultSet.getObject(1); | |
92 | int id = resultSet.getInt(2); | |
93 | logger.debug("Row {}: {}", id, obj.toString()); | |
94 | } | |
95 | ||
96 | } | |
97 | ||
98 | ||
99 | @BeforeClass | |
100 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
101 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
102 | Assert.assertNotNull(jdbcUrlSuffix); | |
103 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
104 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
105 | Assert.assertNotNull(jdbcUsername); | |
106 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
107 | Assert.assertNotNull(jdbcPassword); | |
108 | Class.forName(JDBC_DRIVER_CLASS_NAME); | |
109 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
110 | statement = connection.createStatement(); | |
111 | } | |
112 | ||
113 | ||
114 | @AfterClass | |
115 | public void unallocateDatabaseResources() throws Exception { | |
116 | if ((statement != null) && (!statement.isClosed())) { | |
117 | statement.close(); | |
118 | } | |
119 | if ((connection != null) && (!connection.isClosed())) { | |
120 | connection.close(); | |
121 | } | |
122 | } | |
123 | ||
124 | ||
125 | }⏎ |
0 | /* | |
1 | * VersionPrinter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package org.postgis; | |
26 | ||
27 | ||
28 | import net.postgis.tools.testutils.TestContainerController; | |
29 | import org.postgresql.Driver; | |
30 | import org.slf4j.Logger; | |
31 | import org.slf4j.LoggerFactory; | |
32 | import org.testng.Assert; | |
33 | import org.testng.ITestContext; | |
34 | import org.testng.annotations.AfterClass; | |
35 | import org.testng.annotations.BeforeClass; | |
36 | import org.testng.annotations.Test; | |
37 | ||
38 | import java.sql.*; | |
39 | ||
40 | ||
41 | /** | |
42 | * Prints out as much version information as available. | |
43 | */ | |
44 | public class VersionPrinter { | |
45 | ||
46 | private static final Logger logger = LoggerFactory.getLogger(VersionPrinter.class); | |
47 | ||
48 | private static final String JDBC_DRIVER_CLASS_NAME = "org.postgresql.Driver"; | |
49 | ||
50 | public static String[] POSTGIS_FUNCTIONS = { | |
51 | "postgis_version", | |
52 | "postgis_proj_version", | |
53 | "postgis_scripts_installed", | |
54 | "postgis_lib_version", | |
55 | "postgis_scripts_released", | |
56 | "postgis_uses_stats", | |
57 | "postgis_geos_version", | |
58 | "postgis_scripts_build_date", | |
59 | "postgis_lib_build_date", | |
60 | "postgis_full_version", | |
61 | "postgis_gdal_version", | |
62 | "postgis_libjson_version", | |
63 | "postgis_libxml_version", | |
64 | "postgis_raster_lib_version", | |
65 | "postgis_svn_version" | |
66 | }; | |
67 | ||
68 | private Connection connection = null; | |
69 | ||
70 | private Statement statement = null; | |
71 | ||
72 | ||
73 | @Test | |
74 | public void test() throws Exception { | |
75 | ||
76 | // Print PostGIS version | |
77 | logger.info("*** PostGIS jdbc client code ***"); | |
78 | String fullVersion = Version.getFullVersion(); | |
79 | Assert.assertNotNull(fullVersion); | |
80 | logger.info("\t getFullVersion: {}", fullVersion); | |
81 | ||
82 | // Print PostgreSQL JDBC Versions | |
83 | logger.info("*** PostgreSQL JDBC Driver ***"); | |
84 | String driverVersion = Driver.getVersion(); | |
85 | Assert.assertNotNull(driverVersion); | |
86 | logger.info("\t getVersion: {}", driverVersion); | |
87 | ||
88 | try { | |
89 | Driver driver = new Driver(); | |
90 | int majorVersion = driver.getMajorVersion(); | |
91 | Assert.assertNotEquals(majorVersion, 0); | |
92 | logger.info("\t getMajorVersion: {}", majorVersion); | |
93 | int minorVersion = driver.getMinorVersion(); | |
94 | Assert.assertNotEquals(minorVersion, 0); | |
95 | logger.info("\t getMinorVersion: {}", majorVersion); | |
96 | } catch (Exception e) { | |
97 | logger.error("Cannot create Driver instance: {}", e.getMessage()); | |
98 | } | |
99 | ||
100 | // Print PostgreSQL server versions | |
101 | Assert.assertNotNull(connection); | |
102 | Statement statement = connection.createStatement(); | |
103 | if (statement == null) { | |
104 | logger.info("No online version available."); | |
105 | } else { | |
106 | logger.info("*** PostgreSQL Server ***"); | |
107 | String versionString = getVersionString("version"); | |
108 | logger.debug("\t version: {}", versionString); | |
109 | ||
110 | // Print PostGIS versions | |
111 | logger.info("*** PostGIS Server ***"); | |
112 | for (String GISVERSION : POSTGIS_FUNCTIONS) { | |
113 | versionString = getVersionString(GISVERSION); | |
114 | logger.debug("\t {} version: {}", GISVERSION, versionString); | |
115 | } | |
116 | } | |
117 | } | |
118 | ||
119 | ||
120 | public String getVersionString(String function) throws SQLException { | |
121 | String result = "-- unavailable -- "; | |
122 | try { | |
123 | ResultSet resultSet = statement.executeQuery("SELECT " + function + "()"); | |
124 | if (resultSet.next()) { | |
125 | String version = resultSet.getString(1); | |
126 | if (version != null) { | |
127 | result = version.trim(); | |
128 | } else { | |
129 | result = "-- null result --"; | |
130 | } | |
131 | } else { | |
132 | result = "-- no result --"; | |
133 | } | |
134 | } catch (SQLException sqle) { | |
135 | // If the function does not exist, a SQLException will be thrown, but it should be caught an swallowed if | |
136 | // the "does not exist" string is in the error message. The SQLException might be thrown for some other | |
137 | // problem not related to the missing function, so rethrow it if it doesn't contain the string. | |
138 | if (!sqle.getMessage().contains("does not exist")) { | |
139 | throw sqle; | |
140 | } | |
141 | } | |
142 | return result; | |
143 | } | |
144 | ||
145 | ||
146 | @BeforeClass | |
147 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
148 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
149 | Assert.assertNotNull(jdbcUrlSuffix); | |
150 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
151 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
152 | Assert.assertNotNull(jdbcUsername); | |
153 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
154 | Assert.assertNotNull(jdbcPassword); | |
155 | Class.forName(JDBC_DRIVER_CLASS_NAME); | |
156 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
157 | statement = connection.createStatement(); | |
158 | } | |
159 | ||
160 | ||
161 | @AfterClass | |
162 | public void unallocateDatabaseResources() throws Exception { | |
163 | if ((statement != null) && (!statement.isClosed())) { | |
164 | statement.close(); | |
165 | } | |
166 | if ((connection != null) && (!connection.isClosed())) { | |
167 | connection.close(); | |
168 | } | |
169 | } | |
170 | ||
171 | ||
172 | }⏎ |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2018 Phillip Ross, phillip.w.g.ross@gmail.com | |
16 | */ | |
17 | ||
18 | package org.postgis.util; | |
19 | ||
20 | ||
21 | import net.postgis.tools.testutils.TestContainerController; | |
22 | import org.slf4j.Logger; | |
23 | import org.slf4j.LoggerFactory; | |
24 | import org.testng.Assert; | |
25 | import org.testng.ITestContext; | |
26 | import org.testng.annotations.AfterMethod; | |
27 | import org.testng.annotations.BeforeMethod; | |
28 | import org.testng.annotations.Test; | |
29 | ||
30 | import java.sql.Connection; | |
31 | import java.sql.DriverManager; | |
32 | import java.sql.SQLException; | |
33 | import java.util.StringTokenizer; | |
34 | ||
35 | ||
36 | /** | |
37 | * Integration tests for VersionUtil. | |
38 | * | |
39 | * @author Phillip Ross | |
40 | */ | |
41 | public class VersionUtilIT { | |
42 | ||
43 | /** The static logger instance. */ | |
44 | private static final Logger logger = LoggerFactory.getLogger(VersionUtilIT.class); | |
45 | ||
46 | /** The jdbc url prefix containing the jdbc protocol to be used for tests. */ | |
47 | private static final String JDBC_URL_PROTOCOL_PREFIX = "jdbc:postgresql"; | |
48 | ||
49 | /** The JDBC Connection to be used for tests. */ | |
50 | private Connection connection = null; | |
51 | ||
52 | ||
53 | /** | |
54 | * Initializes a new JDBC Connection. | |
55 | * | |
56 | * @param ctx the test context | |
57 | * @throws Exception when an exception occurs | |
58 | */ | |
59 | @BeforeMethod | |
60 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
61 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
62 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
63 | Assert.assertNotNull(jdbcUrlSuffix); | |
64 | final String jdbcUrl = JDBC_URL_PROTOCOL_PREFIX + jdbcUrlSuffix; | |
65 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
66 | Assert.assertNotNull(jdbcUsername); | |
67 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
68 | Assert.assertNotNull(jdbcPassword); | |
69 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
70 | } | |
71 | ||
72 | ||
73 | /** | |
74 | * Un-allocates the JDBC connection. | |
75 | * | |
76 | * @throws Exception when an exception occurs | |
77 | */ | |
78 | @AfterMethod | |
79 | public void unallocateDatabaseResources() throws Exception { | |
80 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
81 | if ((connection != null) && (!connection.isClosed())) { | |
82 | connection.close(); | |
83 | } | |
84 | } | |
85 | ||
86 | ||
87 | /** | |
88 | * Test getting version string with a null connection. | |
89 | * | |
90 | * @throws Exception when an exception occurs | |
91 | */ | |
92 | @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*null connection.*") | |
93 | public void test_VersionUtil_GetVersionString_NullConnection() throws Exception { | |
94 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
95 | VersionUtil.getVersionString(null, VersionFunctions.POSTGIS_FULL_VERSION.toString()); | |
96 | } | |
97 | ||
98 | ||
99 | /** | |
100 | * Test getting version string with an invalid connection. | |
101 | * | |
102 | * @throws Exception when an exception occurs | |
103 | */ | |
104 | @Test(expectedExceptions = SQLException.class, expectedExceptionsMessageRegExp = ".*connection.*not valid.*") | |
105 | public void test_VersionUtil_GetVersionString_InvalidConnection() throws Exception { | |
106 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
107 | connection.close(); | |
108 | VersionUtil.getVersionString(connection, VersionFunctions.POSTGIS_FULL_VERSION.toString()); | |
109 | } | |
110 | ||
111 | ||
112 | /** | |
113 | * Test getting version string with an invalid function name. | |
114 | * | |
115 | * @throws Exception when an exception occurs | |
116 | */ | |
117 | @Test( | |
118 | expectedExceptions = SQLException.class, | |
119 | expectedExceptionsMessageRegExp = ".*(?!" + VersionUtil.NONEXISTENT_FUNCTION_ERROR_MESSAGE_CONTENT + ")" | |
120 | ) | |
121 | public void test_VersionUtil_GetVersionString_InvalidFunctionName() throws Exception { | |
122 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
123 | VersionUtil.getVersionString(connection, "invalid.function.name"); | |
124 | } | |
125 | ||
126 | ||
127 | /** | |
128 | * Test getting version string with a null function. | |
129 | * | |
130 | * @throws Exception when an exception occurs | |
131 | */ | |
132 | @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*null function.*") | |
133 | public void test_VersionUtil_GetVersionString_NullFunction() throws Exception { | |
134 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
135 | VersionUtil.getVersionString(connection, null); | |
136 | } | |
137 | ||
138 | ||
139 | /** | |
140 | * Test getting version string of an unavailable function. | |
141 | * | |
142 | * @throws Exception when an exception occurs | |
143 | */ | |
144 | @Test | |
145 | public void test_VersionUtil_GetVersionString_Unavailable() throws Exception { | |
146 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
147 | Assert.assertTrue( | |
148 | VersionUtil.getVersionString(connection, "nonexistent") | |
149 | .contains("unavailable") | |
150 | ); | |
151 | } | |
152 | ||
153 | ||
154 | /** | |
155 | * Test getting version strings for all enumerated version functions. | |
156 | * | |
157 | * @throws Exception when an exception occurs | |
158 | */ | |
159 | @Test | |
160 | public void test_VersionUtil_GetVersionString_VersionFunctionsEnum() throws Exception { | |
161 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
162 | for (int i = 0; i < VersionFunctions.values().length; i++) { | |
163 | String function = VersionFunctions.values()[i].toString(); | |
164 | String version = VersionUtil.getVersionString(connection, function); | |
165 | logger.debug("function [{}] => version string [{}]", function, version); | |
166 | } | |
167 | } | |
168 | ||
169 | ||
170 | /** | |
171 | * Test getting the server version string with a null connection. | |
172 | * | |
173 | * @throws Exception when an exception occurs | |
174 | */ | |
175 | @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*null connection.*") | |
176 | public void test_VersionUtil_RetrievePostGISServerVersionString_NullConnection() throws Exception { | |
177 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
178 | VersionUtil.retrievePostGISServerVersionString(null); | |
179 | } | |
180 | ||
181 | ||
182 | /** | |
183 | * Test getting the server version string with an invalid connection. | |
184 | * | |
185 | * @throws Exception when an exception occurs | |
186 | */ | |
187 | @Test(expectedExceptions = SQLException.class, expectedExceptionsMessageRegExp = ".*connection.*not valid.*") | |
188 | public void test_VersionUtil_RetrievePostGISServerVersionString_InvalidConnection() throws Exception { | |
189 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
190 | connection.close(); | |
191 | VersionUtil.retrievePostGISServerVersionString(connection); | |
192 | } | |
193 | ||
194 | ||
195 | /** | |
196 | * Test getting the server version string. | |
197 | * | |
198 | * @throws Exception when an exception occurs | |
199 | */ | |
200 | @Test | |
201 | public void test_VersionUtil_RetrievePostGISServerVersionString() throws Exception { | |
202 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
203 | String postGISServerVersionString = VersionUtil.retrievePostGISServerVersionString(connection); | |
204 | Assert.assertNotNull(postGISServerVersionString); | |
205 | logger.debug("PostGIS server version string [{}]", postGISServerVersionString); | |
206 | } | |
207 | ||
208 | ||
209 | /** | |
210 | * Test getting the server version with a null connection. | |
211 | * | |
212 | * @throws Exception when an exception occurs | |
213 | */ | |
214 | @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*null connection.*") | |
215 | public void test_VersionUtil_RetrievePostGISServerVersion_NullConnection() throws Exception { | |
216 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
217 | VersionUtil.retrievePostGISServerVersion(null); | |
218 | } | |
219 | ||
220 | ||
221 | /** | |
222 | * Test getting the server version with an invalid connection. | |
223 | * | |
224 | * @throws Exception when an exception occurs | |
225 | */ | |
226 | @Test(expectedExceptions = SQLException.class, expectedExceptionsMessageRegExp = ".*connection.*not valid.*") | |
227 | public void test_VersionUtil_RetrievePostGISServerVersion_InvalidConnection() throws Exception { | |
228 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
229 | connection.close(); | |
230 | VersionUtil.retrievePostGISServerVersion(connection); | |
231 | } | |
232 | ||
233 | ||
234 | /** | |
235 | * Test getting the server version. | |
236 | * | |
237 | * @throws Exception when an exception occurs | |
238 | */ | |
239 | @Test | |
240 | public void test_VersionUtil_RetrievePostGISServerVersion() throws Exception { | |
241 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
242 | final String version = VersionUtil.retrievePostGISServerVersion(connection); | |
243 | Assert.assertNotNull(version); | |
244 | logger.debug("PostGIS server version [{}]", version); | |
245 | } | |
246 | ||
247 | ||
248 | /** | |
249 | * Test getting the server major version with a null connection. | |
250 | * | |
251 | * @throws Exception when an exception occurs | |
252 | */ | |
253 | @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*null connection.*") | |
254 | public void test_VersionUtil_RetrievePostGISServerMajorVersion_NullConnection() throws Exception { | |
255 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
256 | VersionUtil.retrievePostGISServerMajorVersion(null); | |
257 | } | |
258 | ||
259 | ||
260 | /** | |
261 | * Test getting the server major version with an invalid connection. | |
262 | * | |
263 | * @throws Exception when an exception occurs | |
264 | */ | |
265 | @Test(expectedExceptions = SQLException.class, expectedExceptionsMessageRegExp = ".*connection.*not valid.*") | |
266 | public void test_VersionUtil_RetrievePostGISServerMajorVersion_InvalidConnection() throws Exception { | |
267 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
268 | connection.close(); | |
269 | VersionUtil.retrievePostGISServerMajorVersion(connection); | |
270 | } | |
271 | ||
272 | ||
273 | /** | |
274 | * Test getting the server major version. | |
275 | * | |
276 | * @throws Exception when an exception occurs | |
277 | */ | |
278 | @Test | |
279 | public void test_VersionUtil_RetrievePostGISServerMajorVersion() throws Exception { | |
280 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
281 | final String version = VersionUtil.retrievePostGISServerMajorVersion(connection); | |
282 | Assert.assertNotNull(version); | |
283 | logger.debug("PostGIS server major version [{}]", version); | |
284 | } | |
285 | ||
286 | ||
287 | /** | |
288 | * Test getting the server minor version with a null connection. | |
289 | * | |
290 | * @throws Exception when an exception occurs | |
291 | */ | |
292 | @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*null connection.*") | |
293 | public void test_VersionUtil_RetrievePostGISServerMinorVersion_NullConnection() throws Exception { | |
294 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
295 | VersionUtil.retrievePostGISServerMinorVersion(null); | |
296 | } | |
297 | ||
298 | ||
299 | /** | |
300 | * Test getting the server minor version with an invalid connection. | |
301 | * | |
302 | * @throws Exception when an exception occurs | |
303 | */ | |
304 | @Test(expectedExceptions = SQLException.class, expectedExceptionsMessageRegExp = ".*connection.*not valid.*") | |
305 | public void test_VersionUtil_RetrievePostGISServerMinorVersion_InvalidConnection() throws Exception { | |
306 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
307 | connection.close(); | |
308 | VersionUtil.retrievePostGISServerMinorVersion(connection); | |
309 | } | |
310 | ||
311 | ||
312 | /** | |
313 | * Test getting the server minor version. | |
314 | * | |
315 | * @throws Exception when an exception occurs | |
316 | */ | |
317 | @Test | |
318 | public void test_VersionUtil_RetrievePostGISServerMinorVersion() throws Exception { | |
319 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
320 | final String version = VersionUtil.retrievePostGISServerMinorVersion(connection); | |
321 | Assert.assertNotNull(version); | |
322 | logger.debug("PostGIS server minor version [{}]", version); | |
323 | } | |
324 | ||
325 | ||
326 | /** | |
327 | * Test additional parsing assertions against retrieved versions. | |
328 | * | |
329 | * @throws Exception when an exception occurs | |
330 | */ | |
331 | @Test | |
332 | public void testServerVersionParsing() throws Exception { | |
333 | logger.trace("[{}.{}]", getClass(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
334 | final String versionString = VersionUtil.retrievePostGISServerVersionString(connection); | |
335 | Assert.assertNotNull(versionString); | |
336 | final String versionFull = VersionUtil.retrievePostGISServerVersion(connection); | |
337 | Assert.assertNotNull(versionFull); | |
338 | Assert.assertTrue(versionString.startsWith(versionFull)); | |
339 | final StringTokenizer stringTokenizer = | |
340 | new StringTokenizer(versionString, VersionUtil.POSTGIS_SERVER_VERSION_SEPERATOR); | |
341 | Assert.assertTrue(stringTokenizer.countTokens() > 0); | |
342 | final String versionMajor = VersionUtil.retrievePostGISServerMajorVersion(connection); | |
343 | Assert.assertEquals(versionMajor, stringTokenizer.nextToken()); | |
344 | if (stringTokenizer.countTokens() > 1) { | |
345 | final String versionMinor = VersionUtil.retrievePostGISServerMinorVersion(connection); | |
346 | Assert.assertEquals(versionMinor, stringTokenizer.nextToken()); | |
347 | } | |
348 | } | |
349 | ||
350 | ||
351 | } |
0 | <configuration debug="false"> | |
1 | ||
2 | <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | |
3 | <layout class="ch.qos.logback.classic.PatternLayout"> | |
4 | <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> | |
5 | </layout> | |
6 | </appender> | |
7 | ||
8 | <root level="debug"> | |
9 | <appender-ref ref="STDOUT" /> | |
10 | </root> | |
11 | ||
12 | <logger name="com.github.dockerjava" level="ERROR"/> | |
13 | <logger name="org.testcontainers" level="ERROR"/> | |
14 | <logger name="net.postgis" level="ERROR"/> | |
15 | ||
16 | <logger name="org.postgis" level="ERROR"/> | |
17 | ||
18 | </configuration>⏎ |
0 | <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> | |
1 | <suite name="Postgis JDBC Extensions Test Suite" verbose="1"> | |
2 | ||
3 | <test name="Postgis JDBC Tests"> | |
4 | <classes> | |
5 | <class name="org.postgis.DatatypesTest"/> | |
6 | <class name="org.postgis.SerializationTest"/> | |
7 | </classes> | |
8 | </test> | |
9 | ||
10 | </suite> |
0 | <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> | |
1 | <suite name="Postgis JDBC Extensions Integration Test Suite" verbose="1"> | |
2 | ||
3 | <parameter name="test.container.image-name" value="${test.container.image}"/> | |
4 | <parameter name="test.container.port" value="${test.db.port}"/> | |
5 | <parameter name="test.container.env.user" value="${test.db.username}"/> | |
6 | <parameter name="test.container.env.password" value="${test.db.password}"/> | |
7 | <parameter name="test.container.env.db" value="${test.db.name}"/> | |
8 | ||
9 | <test name="Postgis JDBC Integration Tests"> | |
10 | <classes> | |
11 | <class name="net.postgis.tools.testutils.TestContainerController"/> | |
12 | <class name="org.postgis.util.VersionUtilIT"/> | |
13 | <class name="org.postgis.DatatypesAutoRegistrationTest"/> | |
14 | <class name="org.postgis.BoxesTest"/> | |
15 | <class name="org.postgis.EmptyGeometriesTest"/> | |
16 | <class name="org.postgis.GeographyDatatypeTest"/> | |
17 | <class name="org.postgis.ParserTest"/> | |
18 | <class name="org.postgis.ServerTest"/> | |
19 | <class name="org.postgis.VersionPrinter"/> | |
20 | </classes> | |
21 | </test> | |
22 | ||
23 | </suite> |
0 | Todo for PostGIS 1.0 compatible JDBC classes | |
1 | ||
2 | - even more Testing, especialy against different postgis, | |
3 | pgjdbc and postgresql releases. | |
4 | ||
5 | - Use JUnit for testing (maven) | |
6 | ||
7 | - Unify the build of app java projects -> maven | |
8 | ||
9 | - Handling of length() - esp. with modifying the geometries | |
10 | ||
11 | - Handling of hashCode() - esp. with modifying the geometries | |
12 | ||
13 | - Test correctness of toString() and getValue() for compatibility reasons | |
14 | ||
15 | - See where the code can be cleaned and leaned. | |
16 | ||
17 | - Finish JTS support | |
18 | ||
19 | - Creating a sane extension interface for pgjdbc that allows binary | |
20 | transfers and convince upstream to use it, then create support for it. | |
21 | ||
22 | - Possibly adding server side code to support plJava | |
23 | http://gborg.postgresql.org/project/pljava/projdisplay.php | |
24 | ||
25 | - Rework the BinaryParser/BinaryWriter to work on SQLInput/SQLOutput | |
26 | instances, as well as reworking ValueGetter/ValueSetter to implment those interfaces. |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
2 | <modelVersion>4.0.0</modelVersion> | |
3 | ||
4 | <parent> | |
5 | <groupId>net.postgis</groupId> | |
6 | <artifactId>postgis-java-aggregator</artifactId> | |
7 | <version>2.5.0</version> | |
8 | </parent> | |
9 | ||
10 | <artifactId>postgis-jdbc-jtsparser</artifactId> | |
11 | <version>2.5.0</version> | |
12 | <packaging>jar</packaging> | |
13 | ||
14 | <name>Postgis JDBC Driver JTS Parser</name> | |
15 | <description>Parser between JTS and PostGIS geometry formats.</description> | |
16 | ||
17 | <properties /> | |
18 | ||
19 | <dependencies> | |
20 | <dependency> | |
21 | <groupId>net.postgis</groupId> | |
22 | <artifactId>postgis-jdbc</artifactId> | |
23 | <version>2.5.0</version> | |
24 | </dependency> | |
25 | <dependency> | |
26 | <groupId>org.locationtech.jts</groupId> | |
27 | <artifactId>jts-core</artifactId> | |
28 | <version>${dependency.jts-version.version}</version> | |
29 | </dependency> | |
30 | <dependency> | |
31 | <groupId>org.locationtech.spatial4j</groupId> | |
32 | <artifactId>spatial4j</artifactId> | |
33 | <version>${dependency.spatial4j.version}</version> | |
34 | </dependency> | |
35 | <dependency> | |
36 | <groupId>net.postgis.tools</groupId> | |
37 | <artifactId>test-utils</artifactId> | |
38 | <version>2.5.0</version> | |
39 | <scope>test</scope> | |
40 | </dependency> | |
41 | </dependencies> | |
42 | ||
43 | <build> | |
44 | <testResources> | |
45 | <testResource> | |
46 | <directory>src/test/resources</directory> | |
47 | </testResource> | |
48 | <testResource> | |
49 | <directory>src/test/resources-filtered</directory> | |
50 | <filtering>true</filtering> | |
51 | </testResource> | |
52 | </testResources> | |
53 | <plugins> | |
54 | <plugin> | |
55 | <groupId>org.apache.maven.plugins</groupId> | |
56 | <artifactId>maven-failsafe-plugin</artifactId> | |
57 | <executions> | |
58 | <execution> | |
59 | <id>integration-tests</id> | |
60 | <goals> | |
61 | <goal>integration-test</goal> | |
62 | <goal>verify</goal> | |
63 | </goals> | |
64 | <configuration> | |
65 | <skip>${maven.integration.test.skip}</skip> | |
66 | <forkCount>${failsafe.forkCount}</forkCount> | |
67 | <useSystemClassLoader>${failsafe.useSystemClassLoader}</useSystemClassLoader> | |
68 | <suiteXmlFiles> | |
69 | <suiteXmlFile>${project.build.testOutputDirectory}/testng-it.xml</suiteXmlFile> | |
70 | </suiteXmlFiles> | |
71 | </configuration> | |
72 | </execution> | |
73 | </executions> | |
74 | </plugin> | |
75 | <plugin> | |
76 | <groupId>org.apache.maven.plugins</groupId> | |
77 | <artifactId>maven-surefire-plugin</artifactId> | |
78 | <configuration> | |
79 | <skip>true</skip> | |
80 | </configuration> | |
81 | </plugin> | |
82 | </plugins> | |
83 | </build> | |
84 | ||
85 | </project> |
0 | /* | |
1 | * JTSShape.java | |
2 | * | |
3 | * Binary Parser for JTS - relies on org.postgis V1.0.0+ package. | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package org.postgis.jts; | |
26 | ||
27 | import org.locationtech.jts.geom.*; | |
28 | import org.locationtech.jts.geom.Point; | |
29 | import org.locationtech.jts.geom.Polygon; | |
30 | import org.locationtech.jts.geom.impl.PackedCoordinateSequence; | |
31 | ||
32 | import java.awt.*; | |
33 | import java.awt.geom.AffineTransform; | |
34 | import java.awt.geom.PathIterator; | |
35 | import java.awt.geom.Point2D; | |
36 | import java.awt.geom.Rectangle2D; | |
37 | ||
38 | public class JTSShape implements Shape { | |
39 | static GeometryFactory fac = new GeometryFactory(); | |
40 | ||
41 | Geometry geom; | |
42 | ||
43 | final static LinearRing[] NOSHELLS = {}; | |
44 | ||
45 | public JTSShape(Geometry _geom) { | |
46 | this.geom = _geom; | |
47 | } | |
48 | ||
49 | public JTSShape(JtsGeometry _geom) { | |
50 | this(_geom.getGeometry()); | |
51 | } | |
52 | ||
53 | public boolean contains(Point2D p) { | |
54 | return contains(p.getX(), p.getY()); | |
55 | } | |
56 | ||
57 | public boolean contains(double x, double y) { | |
58 | Coordinate c = new Coordinate(x, y); | |
59 | Point p = fac.createPoint(c); | |
60 | return geom.contains(p); | |
61 | } | |
62 | ||
63 | public boolean contains(Rectangle2D r) { | |
64 | return contains(r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight()); | |
65 | } | |
66 | ||
67 | public boolean contains(double x, double y, double w, double h) { | |
68 | Polygon p = createRect(x, y, w, h); | |
69 | return geom.contains(p); | |
70 | } | |
71 | ||
72 | protected Polygon createRect(double x, double y, double w, double h) { | |
73 | Coordinate[] coords = { new Coordinate(x, y), new Coordinate(x + w, y), new Coordinate(x + w, y + h) ,new Coordinate(x, y + h) ,new Coordinate(x, y) }; | |
74 | PackedCoordinateSequence shell = new PackedCoordinateSequence.Double(coords, 2); | |
75 | Polygon p = fac.createPolygon(fac.createLinearRing(shell), NOSHELLS); | |
76 | return p; | |
77 | } | |
78 | ||
79 | public Rectangle2D getBounds2D() { | |
80 | Envelope env = geom.getEnvelopeInternal(); | |
81 | return new Rectangle2D.Double(env.getMinX(), env.getMaxX(), env.getWidth(), env.getHeight()); | |
82 | } | |
83 | ||
84 | public Rectangle getBounds() { | |
85 | // We deal simple code for efficiency here, the getBounds() rounding | |
86 | // rules are ugly... | |
87 | return getBounds2D().getBounds(); | |
88 | } | |
89 | ||
90 | public PathIterator getPathIterator(AffineTransform at) { | |
91 | return getPathIterator(geom, at); | |
92 | } | |
93 | ||
94 | public PathIterator getPathIterator(AffineTransform at, double flatness) { | |
95 | // we don't have much work here, as we only have linear segments, no | |
96 | // "flattening" necessary. | |
97 | return getPathIterator(at); | |
98 | } | |
99 | ||
100 | public boolean intersects(Rectangle2D r) { | |
101 | return intersects(r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight()); | |
102 | } | |
103 | ||
104 | public boolean intersects(double x, double y, double w, double h) { | |
105 | Polygon p = createRect(x, y, w, h); | |
106 | return geom.intersects(p); | |
107 | } | |
108 | ||
109 | public static GeometryPathIterator getPathIterator(Geometry geometry, AffineTransform _at) { | |
110 | if (geometry instanceof Point) { | |
111 | return new PointPathIterator((Point) geometry, _at); | |
112 | } else if (geometry instanceof LineString) { | |
113 | return new LineStringPathIterator((LineString) geometry, _at); | |
114 | } else if (geometry instanceof Polygon) { | |
115 | return new PolygonPathIterator((Polygon) geometry, _at); | |
116 | } else { | |
117 | return new GeometryCollectionPathIterator((GeometryCollection) geometry, _at); | |
118 | } | |
119 | } | |
120 | ||
121 | public static abstract class GeometryPathIterator implements PathIterator { | |
122 | ||
123 | protected final AffineTransform at; | |
124 | protected int index=0; | |
125 | ||
126 | GeometryPathIterator(AffineTransform _at) { | |
127 | this.at = _at; | |
128 | } | |
129 | ||
130 | public final int getWindingRule() { | |
131 | return PathIterator.WIND_EVEN_ODD; | |
132 | } | |
133 | ||
134 | public void next() { | |
135 | index++; | |
136 | } | |
137 | } | |
138 | ||
139 | public static class PointPathIterator extends GeometryPathIterator { | |
140 | final Point p; | |
141 | ||
142 | public PointPathIterator(Point _p, AffineTransform _at) { | |
143 | super(_at); | |
144 | p = _p; | |
145 | } | |
146 | ||
147 | public int currentSegment(float[] coords) { | |
148 | switch (index) { | |
149 | case 0: | |
150 | coords[0] = (float) p.getX(); | |
151 | coords[1] = (float) p.getY(); | |
152 | at.transform(coords, 0, coords, 0, 1); | |
153 | return PathIterator.SEG_MOVETO; | |
154 | case 1: | |
155 | return PathIterator.SEG_CLOSE; | |
156 | default: | |
157 | throw new IllegalStateException(); | |
158 | } | |
159 | } | |
160 | ||
161 | public int currentSegment(double[] coords) { | |
162 | switch (index) { | |
163 | case 0: | |
164 | coords[0] = p.getX(); | |
165 | coords[1] = p.getY(); | |
166 | at.transform(coords, 0, coords, 0, 1); | |
167 | return PathIterator.SEG_MOVETO; | |
168 | case 1: | |
169 | return PathIterator.SEG_CLOSE; | |
170 | default: | |
171 | throw new IllegalStateException(); | |
172 | } | |
173 | } | |
174 | ||
175 | public boolean isDone() { | |
176 | return index > 1; | |
177 | } | |
178 | } | |
179 | ||
180 | public static class LineStringPathIterator extends GeometryPathIterator { | |
181 | CoordinateSequence cs; | |
182 | ||
183 | final boolean isRing; | |
184 | ||
185 | public LineStringPathIterator(LineString ls, AffineTransform _at) { | |
186 | super(_at); | |
187 | cs = ls.getCoordinateSequence(); | |
188 | isRing = ls instanceof LinearRing; | |
189 | } | |
190 | ||
191 | /** | |
192 | * only to be called from PolygonPathIterator subclass | |
193 | * @param _cs A coordinate sequence to be used. | |
194 | */ | |
195 | protected void reInit(CoordinateSequence _cs) { | |
196 | cs = _cs; | |
197 | index=0; | |
198 | } | |
199 | ||
200 | public int currentSegment(float[] coords) { | |
201 | if (index == 0) { | |
202 | coords[0] = (float) cs.getOrdinate(index, 0); | |
203 | coords[1] = (float) cs.getOrdinate(index, 1); | |
204 | at.transform(coords, 0, coords, 0, 1); | |
205 | return PathIterator.SEG_MOVETO; | |
206 | } else if (index < cs.size()) { | |
207 | coords[0] = (float) cs.getOrdinate(index, 0); | |
208 | coords[1] = (float) cs.getOrdinate(index, 1); | |
209 | at.transform(coords, 0, coords, 0, 1); | |
210 | return PathIterator.SEG_LINETO; | |
211 | } else if (isRing && index == cs.size()) { | |
212 | return PathIterator.SEG_CLOSE; | |
213 | } else { | |
214 | throw new IllegalStateException(); | |
215 | } | |
216 | } | |
217 | ||
218 | public int currentSegment(double[] coords) { | |
219 | if (index == 0) { | |
220 | coords[0] = cs.getOrdinate(index, 0); | |
221 | coords[1] = cs.getOrdinate(index, 1); | |
222 | at.transform(coords, 0, coords, 0, 1); | |
223 | return PathIterator.SEG_MOVETO; | |
224 | } else if (index < cs.size()) { | |
225 | coords[0] = cs.getOrdinate(index, 0); | |
226 | coords[1] = cs.getOrdinate(index, 1); | |
227 | at.transform(coords, 0, coords, 0, 1); | |
228 | return PathIterator.SEG_LINETO; | |
229 | } else if (isRing && index == cs.size()) { | |
230 | return PathIterator.SEG_CLOSE; | |
231 | } else { | |
232 | throw new IllegalStateException(); | |
233 | } | |
234 | } | |
235 | ||
236 | public boolean isDone() { | |
237 | return isRing ? index > cs.size() : index >= cs.size(); | |
238 | } | |
239 | } | |
240 | ||
241 | public static class PolygonPathIterator extends LineStringPathIterator { | |
242 | final Polygon pg; | |
243 | int outerindex=-1; | |
244 | ||
245 | public PolygonPathIterator(Polygon _pg, AffineTransform _at) { | |
246 | super(_pg.getExteriorRing() ,_at); | |
247 | pg=_pg; | |
248 | index = -1; | |
249 | } | |
250 | ||
251 | public boolean isDone() { | |
252 | return outerindex >= pg.getNumInteriorRing(); | |
253 | } | |
254 | ||
255 | public void next() { | |
256 | super.next(); | |
257 | if (super.isDone()) { | |
258 | outerindex++; | |
259 | if (outerindex < pg.getNumInteriorRing()) { | |
260 | super.reInit(pg.getInteriorRingN(outerindex).getCoordinateSequence()); | |
261 | } | |
262 | } | |
263 | } | |
264 | } | |
265 | ||
266 | public static class GeometryCollectionPathIterator extends GeometryPathIterator { | |
267 | final GeometryCollection coll; | |
268 | GeometryPathIterator current; | |
269 | ||
270 | public GeometryCollectionPathIterator(GeometryCollection _coll, AffineTransform _at) { | |
271 | super(_at); | |
272 | coll = _coll; | |
273 | current = getPathIterator(coll.getGeometryN(index), _at); | |
274 | } | |
275 | ||
276 | public boolean isDone() { | |
277 | return index > coll.getNumGeometries(); | |
278 | } | |
279 | ||
280 | public void next() { | |
281 | current.next(); | |
282 | if (current.isDone()) { | |
283 | index++; | |
284 | if (index < coll.getNumGeometries()) { | |
285 | current = getPathIterator(coll.getGeometryN(index), at); | |
286 | } | |
287 | } | |
288 | } | |
289 | ||
290 | public int currentSegment(float[] coords) { | |
291 | return current.currentSegment(coords); | |
292 | } | |
293 | ||
294 | public int currentSegment(double[] coords) { | |
295 | return current.currentSegment(coords); | |
296 | } | |
297 | } | |
298 | } |
0 | /* | |
1 | * JtsBinaryParser.java | |
2 | * | |
3 | * Binary Parser for JTS - relies on org.postgis V1.0.0+ package. | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | package org.postgis.jts; | |
25 | ||
26 | import org.locationtech.jts.geom.*; | |
27 | import org.locationtech.jts.geom.impl.PackedCoordinateSequence; | |
28 | import org.locationtech.spatial4j.context.jts.JtsSpatialContextFactory; | |
29 | import org.postgis.binary.ByteGetter; | |
30 | import org.postgis.binary.ByteGetter.BinaryByteGetter; | |
31 | import org.postgis.binary.ByteGetter.StringByteGetter; | |
32 | import org.postgis.binary.ValueGetter; | |
33 | ||
34 | /** | |
35 | * Parse binary representation of geometries. Currently, only text rep (hexed) | |
36 | * implementation is tested. | |
37 | * | |
38 | * It should be easy to add char[] and CharSequence ByteGetter instances, | |
39 | * although the latter one is not compatible with older jdks. | |
40 | * | |
41 | * I did not implement real unsigned 32-bit integers or emulate them with long, | |
42 | * as both java Arrays and Strings currently can have only 2^31-1 elements | |
43 | * (bytes), so we cannot even get or build Geometries with more than approx. | |
44 | * 2^28 coordinates (8 bytes each). | |
45 | * | |
46 | * @author Markus Schaber, markus.schaber@logix-tt.com | |
47 | * | |
48 | */ | |
49 | public class JtsBinaryParser { | |
50 | ||
51 | private JtsSpatialContextFactory jtsFactory = new JtsSpatialContextFactory(); | |
52 | ||
53 | /** | |
54 | * Get the appropriate ValueGetter for my endianness | |
55 | * | |
56 | * @param bytes | |
57 | * The appropriate Byte Getter | |
58 | * | |
59 | * @return the ValueGetter | |
60 | */ | |
61 | public static ValueGetter valueGetterForEndian(ByteGetter bytes) { | |
62 | if (bytes.get(0) == ValueGetter.XDR.NUMBER) { // XDR | |
63 | return new ValueGetter.XDR(bytes); | |
64 | } else if (bytes.get(0) == ValueGetter.NDR.NUMBER) { | |
65 | return new ValueGetter.NDR(bytes); | |
66 | } else { | |
67 | throw new IllegalArgumentException("Unknown Endian type:" + bytes.get(0)); | |
68 | } | |
69 | } | |
70 | ||
71 | ||
72 | /** | |
73 | * Parse a hex encoded geometry | |
74 | * @param value String containing the hex data to be parsed | |
75 | * @return the resulting parsed geometry | |
76 | */ | |
77 | public Geometry parse(String value) { | |
78 | StringByteGetter bytes = new ByteGetter.StringByteGetter(value); | |
79 | return parseGeometry(valueGetterForEndian(bytes)); | |
80 | } | |
81 | ||
82 | ||
83 | /** | |
84 | * Parse a binary encoded geometry. | |
85 | * @param value byte array containing the binary encoded geometru | |
86 | * @return the resulting parsed geometry | |
87 | */ | |
88 | public Geometry parse(byte[] value) { | |
89 | BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value); | |
90 | return parseGeometry(valueGetterForEndian(bytes)); | |
91 | } | |
92 | ||
93 | ||
94 | /** | |
95 | * Parse a geometry starting at offset. | |
96 | * @param data ValueGetter for the data to be parsed | |
97 | * @return The resulting Geometry | |
98 | */ | |
99 | protected Geometry parseGeometry(ValueGetter data) { | |
100 | return parseGeometry(data, 0, false); | |
101 | } | |
102 | ||
103 | ||
104 | /** | |
105 | * Parse with a known geometry factory | |
106 | * @param data ValueGetter for the data to be parsed | |
107 | * @param srid the SRID to be used for parsing | |
108 | * @param inheritSrid flag to toggle inheriting SRIDs | |
109 | * @return The resulting Geometry | |
110 | */ | |
111 | protected Geometry parseGeometry(ValueGetter data, int srid, boolean inheritSrid) { | |
112 | byte endian = data.getByte(); // skip and test endian flag | |
113 | if (endian != data.endian) { | |
114 | throw new IllegalArgumentException("Endian inconsistency!"); | |
115 | } | |
116 | int typeword = data.getInt(); | |
117 | ||
118 | int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits | |
119 | ||
120 | boolean haveZ = (typeword & 0x80000000) != 0; | |
121 | boolean haveM = (typeword & 0x40000000) != 0; | |
122 | boolean haveS = (typeword & 0x20000000) != 0; | |
123 | ||
124 | if (haveS) { | |
125 | int newsrid = org.postgis.Geometry.parseSRID(data.getInt()); | |
126 | if (inheritSrid && newsrid != srid) { | |
127 | throw new IllegalArgumentException("Inconsistent srids in complex geometry: " + srid + ", " + newsrid); | |
128 | } else { | |
129 | srid = newsrid; | |
130 | } | |
131 | } else if (!inheritSrid) { | |
132 | srid = org.postgis.Geometry.UNKNOWN_SRID; | |
133 | } | |
134 | ||
135 | Geometry result; | |
136 | switch (realtype) { | |
137 | case org.postgis.Geometry.POINT: | |
138 | result = parsePoint(data, haveZ, haveM); | |
139 | break; | |
140 | case org.postgis.Geometry.LINESTRING: | |
141 | result = parseLineString(data, haveZ, haveM); | |
142 | break; | |
143 | case org.postgis.Geometry.POLYGON: | |
144 | result = parsePolygon(data, haveZ, haveM, srid); | |
145 | break; | |
146 | case org.postgis.Geometry.MULTIPOINT: | |
147 | result = parseMultiPoint(data, srid); | |
148 | break; | |
149 | case org.postgis.Geometry.MULTILINESTRING: | |
150 | result = parseMultiLineString(data, srid); | |
151 | break; | |
152 | case org.postgis.Geometry.MULTIPOLYGON: | |
153 | result = parseMultiPolygon(data, srid); | |
154 | break; | |
155 | case org.postgis.Geometry.GEOMETRYCOLLECTION: | |
156 | result = parseCollection(data, srid); | |
157 | break; | |
158 | default: | |
159 | throw new IllegalArgumentException("Unknown Geometry Type!"); | |
160 | } | |
161 | ||
162 | result.setSRID(srid); | |
163 | ||
164 | return result; | |
165 | } | |
166 | ||
167 | private Point parsePoint(ValueGetter data, boolean haveZ, boolean haveM) { | |
168 | double X = data.getDouble(); | |
169 | double Y = data.getDouble(); | |
170 | Point result; | |
171 | if (haveZ) { | |
172 | double Z = data.getDouble(); | |
173 | result = jtsFactory.getGeometryFactory().createPoint(new Coordinate(X, Y, Z)); | |
174 | } else { | |
175 | result = jtsFactory.getGeometryFactory().createPoint(new Coordinate(X, Y)); | |
176 | } | |
177 | ||
178 | if (haveM) { // skip M value | |
179 | data.getDouble(); | |
180 | } | |
181 | ||
182 | return result; | |
183 | } | |
184 | ||
185 | /** Parse an Array of "full" Geometries */ | |
186 | private void parseGeometryArray(ValueGetter data, Geometry[] container, int srid) { | |
187 | for (int i = 0; i < container.length; i++) { | |
188 | container[i] = parseGeometry(data, srid, true); | |
189 | } | |
190 | } | |
191 | ||
192 | /** | |
193 | * Parse an Array of "slim" Points (without endianness and type, part of | |
194 | * LinearRing and Linestring, but not MultiPoint! | |
195 | * | |
196 | * @param haveZ | |
197 | * @param haveM | |
198 | */ | |
199 | private CoordinateSequence parseCS(ValueGetter data, boolean haveZ, boolean haveM) { | |
200 | int count = data.getInt(); | |
201 | int dims = haveZ ? 3 : 2; | |
202 | CoordinateSequence cs = new PackedCoordinateSequence.Double(count, dims, 0); | |
203 | ||
204 | for (int i = 0; i < count; i++) { | |
205 | for (int d = 0; d < dims; d++) { | |
206 | cs.setOrdinate(i, d, data.getDouble()); | |
207 | } | |
208 | if (haveM) { // skip M value | |
209 | data.getDouble(); | |
210 | } | |
211 | } | |
212 | return cs; | |
213 | } | |
214 | ||
215 | private MultiPoint parseMultiPoint(ValueGetter data, int srid) { | |
216 | Point[] points = new Point[data.getInt()]; | |
217 | parseGeometryArray(data, points, srid); | |
218 | return jtsFactory.getGeometryFactory().createMultiPoint(points); | |
219 | } | |
220 | ||
221 | private LineString parseLineString(ValueGetter data, boolean haveZ, boolean haveM) { | |
222 | return jtsFactory.getGeometryFactory().createLineString(parseCS(data, haveZ, haveM)); | |
223 | } | |
224 | ||
225 | private LinearRing parseLinearRing(ValueGetter data, boolean haveZ, boolean haveM) { | |
226 | return jtsFactory.getGeometryFactory().createLinearRing(parseCS(data, haveZ, haveM)); | |
227 | } | |
228 | ||
229 | private Polygon parsePolygon(ValueGetter data, boolean haveZ, boolean haveM, int srid) { | |
230 | int holecount = data.getInt() - 1; | |
231 | LinearRing[] rings = new LinearRing[holecount]; | |
232 | LinearRing shell = parseLinearRing(data, haveZ, haveM); | |
233 | shell.setSRID(srid); | |
234 | for (int i = 0; i < holecount; i++) { | |
235 | rings[i] = parseLinearRing(data, haveZ, haveM); | |
236 | rings[i].setSRID(srid); | |
237 | } | |
238 | return jtsFactory.getGeometryFactory().createPolygon(shell, rings); | |
239 | } | |
240 | ||
241 | private MultiLineString parseMultiLineString(ValueGetter data, int srid) { | |
242 | int count = data.getInt(); | |
243 | LineString[] strings = new LineString[count]; | |
244 | parseGeometryArray(data, strings, srid); | |
245 | return jtsFactory.getGeometryFactory().createMultiLineString(strings); | |
246 | } | |
247 | ||
248 | private MultiPolygon parseMultiPolygon(ValueGetter data, int srid) { | |
249 | int count = data.getInt(); | |
250 | Polygon[] polys = new Polygon[count]; | |
251 | parseGeometryArray(data, polys, srid); | |
252 | return jtsFactory.getGeometryFactory().createMultiPolygon(polys); | |
253 | } | |
254 | ||
255 | private GeometryCollection parseCollection(ValueGetter data, int srid) { | |
256 | int count = data.getInt(); | |
257 | Geometry[] geoms = new Geometry[count]; | |
258 | parseGeometryArray(data, geoms, srid); | |
259 | return jtsFactory.getGeometryFactory().createGeometryCollection(geoms); | |
260 | } | |
261 | } |
0 | /* | |
1 | * JtsBinaryWriter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Writer | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | package org.postgis.jts; | |
25 | ||
26 | import org.locationtech.jts.geom.CoordinateSequence; | |
27 | import org.locationtech.jts.geom.Geometry; | |
28 | import org.locationtech.jts.geom.GeometryCollection; | |
29 | import org.locationtech.jts.geom.LineString; | |
30 | import org.locationtech.jts.geom.MultiLineString; | |
31 | import org.locationtech.jts.geom.MultiPoint; | |
32 | import org.locationtech.jts.geom.MultiPolygon; | |
33 | import org.locationtech.jts.geom.Point; | |
34 | import org.locationtech.jts.geom.Polygon; | |
35 | ||
36 | import org.postgis.binary.ByteSetter; | |
37 | import org.postgis.binary.ValueSetter; | |
38 | ||
39 | /** | |
40 | * Create binary representation of geometries. Currently, only text rep (hexed) | |
41 | * implementation is tested. Supports only 2 dimensional geometries. | |
42 | * | |
43 | * It should be easy to add char[] and CharSequence ByteGetter instances, | |
44 | * although the latter one is not compatible with older jdks. | |
45 | * | |
46 | * I did not implement real unsigned 32-bit integers or emulate them with long, | |
47 | * as both java Arrays and Strings currently can have only 2^31-1 elements | |
48 | * (bytes), so we cannot even get or build Geometries with more than approx. | |
49 | * 2^28 coordinates (8 bytes each). | |
50 | * | |
51 | * @author markus.schaber@logi-track.com | |
52 | * | |
53 | */ | |
54 | public class JtsBinaryWriter { | |
55 | ||
56 | /** | |
57 | * Get the appropriate ValueGetter for my endianness | |
58 | * | |
59 | * @param bytes The ByteSetter | |
60 | * @param endian The endian to be used | |
61 | * @return the appropriate ValueSetter for the specified endian | |
62 | */ | |
63 | public static ValueSetter valueSetterForEndian(ByteSetter bytes, byte endian) { | |
64 | if (endian == ValueSetter.XDR.NUMBER) { // XDR | |
65 | return new ValueSetter.XDR(bytes); | |
66 | } else if (endian == ValueSetter.NDR.NUMBER) { | |
67 | return new ValueSetter.NDR(bytes); | |
68 | } else { | |
69 | throw new IllegalArgumentException("Unknown Endian type:" + endian); | |
70 | } | |
71 | } | |
72 | ||
73 | /** | |
74 | * Write a hex encoded geometry | |
75 | * | |
76 | * Currently, geometries with more than 2 dimensions and measures are not | |
77 | * cleanly supported, but SRID is honored. | |
78 | * | |
79 | * @param geom The geometry to be written | |
80 | * @param REP The endianness representation to use for writing | |
81 | * @return String containing the hex-encoded geometry | |
82 | */ | |
83 | public String writeHexed(Geometry geom, byte REP) { | |
84 | int length = estimateBytes(geom); | |
85 | ByteSetter.StringByteSetter bytes = new ByteSetter.StringByteSetter(length); | |
86 | writeGeometry(geom, valueSetterForEndian(bytes, REP)); | |
87 | return bytes.result(); | |
88 | } | |
89 | ||
90 | public String writeHexed(Geometry geom) { | |
91 | return writeHexed(geom, ValueSetter.NDR.NUMBER); | |
92 | } | |
93 | ||
94 | /** | |
95 | * Write a binary encoded geometry. | |
96 | * | |
97 | * Currently, geometries with more than 2 dimensions and measures are not | |
98 | * cleanly supported, but SRID is honored. | |
99 | * | |
100 | * @param geom The geometry to be written | |
101 | * @param REP The endianness representation to use for writing | |
102 | * @return byte array containing the encoded geometry | |
103 | */ | |
104 | public byte[] writeBinary(Geometry geom, byte REP) { | |
105 | int length = estimateBytes(geom); | |
106 | ByteSetter.BinaryByteSetter bytes = new ByteSetter.BinaryByteSetter(length); | |
107 | writeGeometry(geom, valueSetterForEndian(bytes, REP)); | |
108 | return bytes.result(); | |
109 | } | |
110 | ||
111 | public byte[] writeBinary(Geometry geom) { | |
112 | return writeBinary(geom, ValueSetter.NDR.NUMBER); | |
113 | } | |
114 | ||
115 | ||
116 | /** | |
117 | * Parse a geometry starting at offset. | |
118 | * @param geom The Geometry to be written | |
119 | * @param dest The ValueSettr to write to | |
120 | */ | |
121 | protected void writeGeometry(Geometry geom, ValueSetter dest) { | |
122 | final int dimension; | |
123 | if (geom == null) { | |
124 | throw new NullPointerException(); | |
125 | } else if (geom.isEmpty()) { | |
126 | // don't set any flag bits | |
127 | dimension = 0; | |
128 | } else { | |
129 | dimension = getCoordDim(geom); | |
130 | if (dimension < 2 || dimension > 4) { | |
131 | throw new IllegalArgumentException("Unsupported geometry dimensionality: " + dimension); | |
132 | } | |
133 | } | |
134 | // write endian flag | |
135 | dest.setByte(dest.endian); | |
136 | ||
137 | // write typeword | |
138 | final int plaintype = getWKBType(geom); | |
139 | int typeword = plaintype; | |
140 | if (dimension == 3 || dimension == 4) { | |
141 | typeword |= 0x80000000; | |
142 | } | |
143 | if (dimension == 4) { | |
144 | typeword |= 0x40000000; | |
145 | } | |
146 | ||
147 | final boolean haveSrid = checkSrid(geom); | |
148 | if (haveSrid) { | |
149 | typeword |= 0x20000000; | |
150 | } | |
151 | ||
152 | dest.setInt(typeword); | |
153 | ||
154 | if (haveSrid) { | |
155 | dest.setInt(geom.getSRID()); | |
156 | } | |
157 | ||
158 | switch (plaintype) { | |
159 | case org.postgis.Geometry.POINT: | |
160 | writePoint((Point) geom, dest); | |
161 | break; | |
162 | case org.postgis.Geometry.LINESTRING: | |
163 | writeLineString((LineString) geom, dest); | |
164 | break; | |
165 | case org.postgis.Geometry.POLYGON: | |
166 | writePolygon((Polygon) geom, dest); | |
167 | break; | |
168 | case org.postgis.Geometry.MULTIPOINT: | |
169 | writeMultiPoint((MultiPoint) geom, dest); | |
170 | break; | |
171 | case org.postgis.Geometry.MULTILINESTRING: | |
172 | writeMultiLineString((MultiLineString) geom, dest); | |
173 | break; | |
174 | case org.postgis.Geometry.MULTIPOLYGON: | |
175 | writeMultiPolygon((MultiPolygon) geom, dest); | |
176 | break; | |
177 | case org.postgis.Geometry.GEOMETRYCOLLECTION: | |
178 | writeCollection((GeometryCollection) geom, dest); | |
179 | break; | |
180 | default: | |
181 | throw new IllegalArgumentException("Unknown Geometry Type: " + plaintype); | |
182 | } | |
183 | } | |
184 | ||
185 | public static int getWKBType(Geometry geom) { | |
186 | // We always write empty geometries as empty collections - for OpenGIS | |
187 | // conformance | |
188 | if (geom.isEmpty()) { | |
189 | return org.postgis.Geometry.GEOMETRYCOLLECTION; | |
190 | } else if (geom instanceof Point) { | |
191 | return org.postgis.Geometry.POINT; | |
192 | } else if (geom instanceof org.locationtech.jts.geom.LineString) { | |
193 | return org.postgis.Geometry.LINESTRING; | |
194 | } else if (geom instanceof org.locationtech.jts.geom.Polygon) { | |
195 | return org.postgis.Geometry.POLYGON; | |
196 | } else if (geom instanceof MultiPoint) { | |
197 | return org.postgis.Geometry.MULTIPOINT; | |
198 | } else if (geom instanceof MultiLineString) { | |
199 | return org.postgis.Geometry.MULTILINESTRING; | |
200 | } else if (geom instanceof org.locationtech.jts.geom.MultiPolygon) { | |
201 | return org.postgis.Geometry.MULTIPOLYGON; | |
202 | } if (geom instanceof org.locationtech.jts.geom.GeometryCollection) { | |
203 | return org.postgis.Geometry.GEOMETRYCOLLECTION; | |
204 | } else { | |
205 | throw new IllegalArgumentException("Unknown Geometry Type: " + geom.getClass().getName()); | |
206 | } | |
207 | } | |
208 | ||
209 | /** | |
210 | * Writes a "slim" Point (without endiannes, srid ant type, only the | |
211 | * ordinates and measure. Used by writeGeometry. | |
212 | */ | |
213 | private void writePoint(Point geom, ValueSetter dest) { | |
214 | writeCoordinates(geom.getCoordinateSequence(), getCoordDim(geom), dest); | |
215 | } | |
216 | ||
217 | /** | |
218 | * Write a CoordinateSequence, part of LinearRing and Linestring, but not | |
219 | * MultiPoint! | |
220 | */ | |
221 | private void writeCoordinates(CoordinateSequence seq, int dims, ValueSetter dest) { | |
222 | for (int i = 0; i < seq.size(); i++) { | |
223 | for (int d = 0; d < dims; d++) { | |
224 | dest.setDouble(seq.getOrdinate(i, d)); | |
225 | } | |
226 | } | |
227 | } | |
228 | ||
229 | private void writeMultiPoint(MultiPoint geom, ValueSetter dest) { | |
230 | dest.setInt(geom.getNumPoints()); | |
231 | for (int i = 0; i < geom.getNumPoints(); i++) { | |
232 | writeGeometry(geom.getGeometryN(i), dest); | |
233 | } | |
234 | } | |
235 | ||
236 | private void writeLineString(LineString geom, ValueSetter dest) { | |
237 | dest.setInt(geom.getNumPoints()); | |
238 | writeCoordinates(geom.getCoordinateSequence(), getCoordDim(geom), dest); | |
239 | } | |
240 | ||
241 | private void writePolygon(Polygon geom, ValueSetter dest) { | |
242 | dest.setInt(geom.getNumInteriorRing() + 1); | |
243 | writeLineString(geom.getExteriorRing(), dest); | |
244 | for (int i = 0; i < geom.getNumInteriorRing(); i++) { | |
245 | writeLineString(geom.getInteriorRingN(i), dest); | |
246 | } | |
247 | } | |
248 | ||
249 | private void writeMultiLineString(MultiLineString geom, ValueSetter dest) { | |
250 | writeGeometryArray(geom, dest); | |
251 | } | |
252 | ||
253 | private void writeMultiPolygon(MultiPolygon geom, ValueSetter dest) { | |
254 | writeGeometryArray(geom, dest); | |
255 | } | |
256 | ||
257 | private void writeCollection(GeometryCollection geom, ValueSetter dest) { | |
258 | writeGeometryArray(geom, dest); | |
259 | } | |
260 | ||
261 | private void writeGeometryArray(Geometry geom, ValueSetter dest) { | |
262 | dest.setInt(geom.getNumGeometries()); | |
263 | for (int i = 0; i < geom.getNumGeometries(); i++) { | |
264 | writeGeometry(geom.getGeometryN(i), dest); | |
265 | } | |
266 | } | |
267 | ||
268 | ||
269 | /** | |
270 | * Estimate how much bytes a geometry will need in WKB. | |
271 | * @param geom Geometry to estimate | |
272 | * @return number of bytes needed | |
273 | */ | |
274 | protected int estimateBytes(Geometry geom) { | |
275 | int result = 0; | |
276 | ||
277 | // write endian flag | |
278 | result += 1; | |
279 | ||
280 | // write typeword | |
281 | result += 4; | |
282 | ||
283 | if (checkSrid(geom)) { | |
284 | result += 4; | |
285 | } | |
286 | ||
287 | switch (getWKBType(geom)) { | |
288 | case org.postgis.Geometry.POINT: | |
289 | result += estimatePoint((Point) geom); | |
290 | break; | |
291 | case org.postgis.Geometry.LINESTRING: | |
292 | result += estimateLineString((LineString) geom); | |
293 | break; | |
294 | case org.postgis.Geometry.POLYGON: | |
295 | result += estimatePolygon((Polygon) geom); | |
296 | break; | |
297 | case org.postgis.Geometry.MULTIPOINT: | |
298 | result += estimateMultiPoint((MultiPoint) geom); | |
299 | break; | |
300 | case org.postgis.Geometry.MULTILINESTRING: | |
301 | result += estimateMultiLineString((MultiLineString) geom); | |
302 | break; | |
303 | case org.postgis.Geometry.MULTIPOLYGON: | |
304 | result += estimateMultiPolygon((MultiPolygon) geom); | |
305 | break; | |
306 | case org.postgis.Geometry.GEOMETRYCOLLECTION: | |
307 | result += estimateCollection((GeometryCollection) geom); | |
308 | break; | |
309 | default: | |
310 | throw new IllegalArgumentException("Unknown Geometry Type: " + getWKBType(geom)); | |
311 | } | |
312 | return result; | |
313 | } | |
314 | ||
315 | private boolean checkSrid(Geometry geom) { | |
316 | final int srid = geom.getSRID(); | |
317 | return (srid > 0); | |
318 | } | |
319 | ||
320 | private int estimatePoint(Point geom) { | |
321 | return 8 * getCoordDim(geom); | |
322 | } | |
323 | ||
324 | /** Write an Array of "full" Geometries */ | |
325 | private int estimateGeometryArray(Geometry container) { | |
326 | int result = 0; | |
327 | for (int i = 0; i < container.getNumGeometries(); i++) { | |
328 | result += estimateBytes(container.getGeometryN(i)); | |
329 | } | |
330 | return result; | |
331 | } | |
332 | ||
333 | /** Estimate an array of "fat" Points */ | |
334 | private int estimateMultiPoint(MultiPoint geom) { | |
335 | // int size | |
336 | int result = 4; | |
337 | if (geom.getNumGeometries() > 0) { | |
338 | // We can shortcut here, compared to estimateGeometryArray, as all | |
339 | // subgeoms have the same fixed size | |
340 | result += geom.getNumGeometries() * estimateBytes(geom.getGeometryN(0)); | |
341 | } | |
342 | return result; | |
343 | } | |
344 | ||
345 | private int estimateLineString(LineString geom) { | |
346 | if (geom == null || geom.getNumGeometries() == 0) { | |
347 | return 0; | |
348 | } else { | |
349 | return 4 + 8 * getCoordSequenceDim(geom.getCoordinateSequence()) * geom.getCoordinateSequence().size(); | |
350 | } | |
351 | } | |
352 | ||
353 | private int estimatePolygon(Polygon geom) { | |
354 | // int length | |
355 | int result = 4; | |
356 | result += estimateLineString(geom.getExteriorRing()); | |
357 | for (int i = 0; i < geom.getNumInteriorRing(); i++) { | |
358 | result += estimateLineString(geom.getInteriorRingN(i)); | |
359 | } | |
360 | return result; | |
361 | } | |
362 | ||
363 | private int estimateMultiLineString(MultiLineString geom) { | |
364 | // 4-byte count + subgeometries | |
365 | return 4 + estimateGeometryArray(geom); | |
366 | } | |
367 | ||
368 | private int estimateMultiPolygon(MultiPolygon geom) { | |
369 | // 4-byte count + subgeometries | |
370 | return 4 + estimateGeometryArray(geom); | |
371 | } | |
372 | ||
373 | private int estimateCollection(GeometryCollection geom) { | |
374 | // 4-byte count + subgeometries | |
375 | return 4 + estimateGeometryArray(geom); | |
376 | } | |
377 | ||
378 | public static final int getCoordDim(Geometry geom) { | |
379 | if (geom.isEmpty()) { | |
380 | return 0; | |
381 | } | |
382 | if (geom instanceof Point) { | |
383 | return getCoordSequenceDim(((Point) geom).getCoordinateSequence()); | |
384 | } else if (geom instanceof LineString) { | |
385 | return getCoordSequenceDim(((LineString) geom).getCoordinateSequence()); | |
386 | } else if (geom instanceof Polygon) { | |
387 | return getCoordSequenceDim(((Polygon) geom).getExteriorRing().getCoordinateSequence()); | |
388 | } else { | |
389 | return getCoordDim(geom.getGeometryN(0)); | |
390 | } | |
391 | } | |
392 | ||
393 | public static final int getCoordSequenceDim(CoordinateSequence coords) { | |
394 | if (coords == null || coords.size() == 0) | |
395 | return 0; | |
396 | // JTS has a really strange way to handle dimensions! | |
397 | // Just have a look at PackedCoordinateSequence and | |
398 | // CoordinateArraySequence | |
399 | int dimensions = coords.getDimension(); | |
400 | if (dimensions == 3) { | |
401 | // CoordinateArraySequence will always return 3, so we have to | |
402 | // check, if | |
403 | // the third ordinate contains NaN, then the geom is actually | |
404 | // 2-dimensional | |
405 | return Double.isNaN(coords.getOrdinate(0, CoordinateSequence.Z)) ? 2 : 3; | |
406 | } else { | |
407 | return dimensions; | |
408 | } | |
409 | } | |
410 | } |
0 | /* | |
1 | * JtsGeometry.java | |
2 | * | |
3 | * Wrapper for PostgreSQL JDBC driver to allow transparent reading and writing | |
4 | * of JTS geometries | |
5 | * | |
6 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
7 | * | |
8 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public | |
21 | * License along with this library; if not, write to the Free Software | |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
23 | * | |
24 | */ | |
25 | ||
26 | package org.postgis.jts; | |
27 | ||
28 | import java.sql.SQLException; | |
29 | ||
30 | import org.postgresql.util.PGobject; | |
31 | ||
32 | import org.locationtech.jts.geom.CoordinateSequenceFactory; | |
33 | import org.locationtech.jts.geom.Geometry; | |
34 | import org.locationtech.jts.geom.GeometryCollection; | |
35 | import org.locationtech.jts.geom.GeometryFactory; | |
36 | import org.locationtech.jts.geom.Polygon; | |
37 | import org.locationtech.jts.geom.PrecisionModel; | |
38 | import org.locationtech.jts.geom.impl.PackedCoordinateSequenceFactory; | |
39 | import org.locationtech.jts.io.WKTReader; | |
40 | ||
41 | /** | |
42 | * JTS Geometry SQL wrapper. Supports PostGIS 1.x (lwgeom hexwkb) for writing | |
43 | * and both PostGIS 0.x (EWKT) and 1.x (lwgeom hexwkb) for reading. | |
44 | * | |
45 | * @author Markus Schaber | |
46 | */ | |
47 | ||
48 | public class JtsGeometry extends PGobject { | |
49 | /* JDK 1.5 Serialization */ | |
50 | private static final long serialVersionUID = 0x100; | |
51 | ||
52 | Geometry geom; | |
53 | ||
54 | final static JtsBinaryParser bp = new JtsBinaryParser(); | |
55 | ||
56 | final static JtsBinaryWriter bw = new JtsBinaryWriter(); | |
57 | ||
58 | final static PrecisionModel prec = new PrecisionModel(); | |
59 | ||
60 | final static CoordinateSequenceFactory csfac = PackedCoordinateSequenceFactory.DOUBLE_FACTORY; | |
61 | ||
62 | final static GeometryFactory geofac = new GeometryFactory(prec, 0, csfac); | |
63 | ||
64 | static final WKTReader reader = new WKTReader(geofac); | |
65 | ||
66 | /** Constructor called by JDBC drivers */ | |
67 | public JtsGeometry() { | |
68 | setType("geometry"); | |
69 | } | |
70 | ||
71 | public JtsGeometry(Geometry geom) { | |
72 | this(); | |
73 | this.geom = geom; | |
74 | } | |
75 | ||
76 | public JtsGeometry(String value) throws SQLException { | |
77 | this(); | |
78 | setValue(value); | |
79 | } | |
80 | ||
81 | public void setValue(String value) throws SQLException { | |
82 | geom = geomFromString(value); | |
83 | } | |
84 | ||
85 | public static Geometry geomFromString(String value) throws SQLException { | |
86 | try { | |
87 | value = value.trim(); | |
88 | if (value.startsWith("00") || value.startsWith("01")) { | |
89 | return bp.parse(value); | |
90 | } else { | |
91 | Geometry result; | |
92 | // no srid := 0 in JTS world | |
93 | int srid = 0; | |
94 | // break up geometry into srid and wkt | |
95 | if (value.startsWith("SRID=")) { | |
96 | String[] temp = value.split(";"); | |
97 | value = temp[1].trim(); | |
98 | srid = Integer.parseInt(temp[0].substring(5)); | |
99 | } | |
100 | ||
101 | result = reader.read(value); | |
102 | setSridRecurse(result, srid); | |
103 | return result; | |
104 | } | |
105 | } catch (Exception E) { | |
106 | E.printStackTrace(); | |
107 | throw new SQLException("Error parsing SQL data:" + E); | |
108 | } | |
109 | } | |
110 | ||
111 | ||
112 | /** | |
113 | * Recursively set a srid for the geometry and all subgeometries | |
114 | * @param geom Geometry to work on | |
115 | * @param srid SRID to be set to | |
116 | */ | |
117 | public static void setSridRecurse(final Geometry geom, final int srid) { | |
118 | geom.setSRID(srid); | |
119 | if (geom instanceof GeometryCollection) { | |
120 | final int subcnt = geom.getNumGeometries(); | |
121 | for (int i = 0; i < subcnt; i++) { | |
122 | setSridRecurse(geom.getGeometryN(i), srid); | |
123 | } | |
124 | } else if (geom instanceof Polygon) { | |
125 | Polygon poly = (Polygon) geom; | |
126 | poly.getExteriorRing().setSRID(srid); | |
127 | final int subcnt = poly.getNumInteriorRing(); | |
128 | for (int i = 0; i < subcnt; i++) { | |
129 | poly.getInteriorRingN(i).setSRID(srid); | |
130 | } | |
131 | } | |
132 | } | |
133 | ||
134 | public Geometry getGeometry() { | |
135 | return geom; | |
136 | } | |
137 | ||
138 | public String toString() { | |
139 | return geom.toString(); | |
140 | } | |
141 | ||
142 | public String getValue() { | |
143 | return bw.writeHexed(getGeometry()); | |
144 | } | |
145 | ||
146 | public Object clone() { | |
147 | JtsGeometry obj = new JtsGeometry(geom); | |
148 | obj.setType(type); | |
149 | return obj; | |
150 | } | |
151 | ||
152 | public boolean equals(Object obj) { | |
153 | if ((obj != null) && (obj instanceof JtsGeometry)) { | |
154 | Geometry other = ((JtsGeometry) obj).geom; | |
155 | if (this.geom == other) { // handles identity as well as both | |
156 | // ==null | |
157 | return true; | |
158 | } else if (this.geom != null && other != null) { | |
159 | return other.equals(this.geom); | |
160 | } | |
161 | } | |
162 | return false; | |
163 | } | |
164 | } |
0 | /* | |
1 | * JtsGisWrapper.java | |
2 | * | |
3 | * Allows transparent usage of JTS Geometry classes via PostgreSQL JDBC driver | |
4 | * connected to a PostGIS enabled PostgreSQL server. | |
5 | * | |
6 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
7 | * | |
8 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public | |
21 | * License along with this library; if not, write to the Free Software | |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
23 | * | |
24 | */ | |
25 | ||
26 | package org.postgis.jts; | |
27 | ||
28 | import org.postgresql.Driver; | |
29 | import org.postgresql.PGConnection; | |
30 | ||
31 | import java.sql.Connection; | |
32 | import java.sql.SQLException; | |
33 | import java.util.Properties; | |
34 | ||
35 | /** | |
36 | * JtsGisWrapper | |
37 | * | |
38 | * Wraps the PostGreSQL Driver to add the JTS/PostGIS Object Classes. | |
39 | * | |
40 | * This method currently works with J2EE DataSource implementations, and with | |
41 | * DriverManager framework. | |
42 | * | |
43 | * Simply replace the "jdbc:postgresql:" with a "jdbc:postgresql_JTS" in the | |
44 | * jdbc URL. | |
45 | * | |
46 | * @author markus.schaber@logix-tt.com | |
47 | * | |
48 | */ | |
49 | public class JtsGisWrapper extends Driver { | |
50 | ||
51 | private static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; | |
52 | private static final String POSTGIS_PROTOCOL = "jdbc:postgresql_JTS:"; | |
53 | public static final String REVISION = "$Revision$"; | |
54 | ||
55 | public JtsGisWrapper() { | |
56 | super(); | |
57 | } | |
58 | ||
59 | static { | |
60 | try { | |
61 | // Analogy to org.postgresql.Driver | |
62 | java.sql.DriverManager.registerDriver(new JtsGisWrapper()); | |
63 | } catch (SQLException e) { | |
64 | e.printStackTrace(); | |
65 | } | |
66 | } | |
67 | ||
68 | /** | |
69 | * Creates a postgresql connection, and then adds the PostGIS data types to | |
70 | * it calling addpgtypes() | |
71 | * | |
72 | * @param url the URL of the database to connect to | |
73 | * @param info a list of arbitrary tag/value pairs as connection arguments | |
74 | * @return a connection to the URL or null if it isnt us | |
75 | * @exception SQLException if a database access error occurs | |
76 | * | |
77 | * @see java.sql.Driver#connect | |
78 | * @see org.postgresql.Driver | |
79 | */ | |
80 | public java.sql.Connection connect(String url, Properties info) throws SQLException { | |
81 | url = mangleURL(url); | |
82 | Connection result = super.connect(url, info); | |
83 | addGISTypes((PGConnection) result); | |
84 | return result; | |
85 | } | |
86 | ||
87 | /** | |
88 | * Adds the JTS/PostGIS Data types to a PG Connection. | |
89 | * @param pgconn The PGConnection object to add the types to | |
90 | * @throws SQLException when an SQLException occurs | |
91 | */ | |
92 | public static void addGISTypes(PGConnection pgconn) throws SQLException { | |
93 | pgconn.addDataType("geometry", org.postgis.jts.JtsGeometry.class); | |
94 | pgconn.addDataType("box3d", org.postgis.PGbox3d.class); | |
95 | pgconn.addDataType("box2d", org.postgis.PGbox2d.class); | |
96 | } | |
97 | ||
98 | /** | |
99 | * Mangles the PostGIS URL to return the original PostGreSQL URL | |
100 | * | |
101 | * @param url String containing the url to be "mangled" | |
102 | * @return "mangled" string | |
103 | * @throws SQLException when a SQLException occurs | |
104 | */ | |
105 | public static String mangleURL(String url) throws SQLException { | |
106 | if (url.startsWith(POSTGIS_PROTOCOL)) { | |
107 | return POSTGRES_PROTOCOL + url.substring(POSTGIS_PROTOCOL.length()); | |
108 | } else { | |
109 | throw new SQLException("Unknown protocol or subprotocol in url " + url); | |
110 | } | |
111 | } | |
112 | ||
113 | /** | |
114 | * Returns true if the driver thinks it can open a connection to the given | |
115 | * URL. Typically, drivers will return true if they understand the | |
116 | * subprotocol specified in the URL and false if they don't. Our protocols | |
117 | * start with jdbc:postgresql_postGIS: | |
118 | * | |
119 | * @see java.sql.Driver#acceptsURL | |
120 | * @param url the URL of the driver | |
121 | * @return true if this driver accepts the given URL | |
122 | */ | |
123 | public boolean acceptsURL(String url) { | |
124 | try { | |
125 | url = mangleURL(url); | |
126 | } catch (SQLException e) { | |
127 | return false; | |
128 | } | |
129 | return super.acceptsURL(url); | |
130 | } | |
131 | ||
132 | /** | |
133 | * Gets the underlying drivers major version number | |
134 | * | |
135 | * @return the drivers major version number | |
136 | */ | |
137 | ||
138 | public int getMajorVersion() { | |
139 | return super.getMajorVersion(); | |
140 | } | |
141 | ||
142 | /** | |
143 | * Get the underlying drivers minor version number | |
144 | * | |
145 | * @return the drivers minor version number | |
146 | */ | |
147 | public int getMinorVersion() { | |
148 | return super.getMinorVersion(); | |
149 | } | |
150 | ||
151 | /** | |
152 | * Returns our own CVS version plus postgres Version | |
153 | * | |
154 | * @return String representation of the version | |
155 | */ | |
156 | public static String getVersion() { | |
157 | return "JtsGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); | |
158 | } | |
159 | } |
0 | /* | |
1 | * JtsWrapper.java | |
2 | * | |
3 | * Allows transparent usage of JTS Geometry classes via PostgreSQL JDBC driver | |
4 | * connected to a PostGIS enabled PostgreSQL server. | |
5 | * | |
6 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
7 | * | |
8 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public | |
21 | * License along with this library; if not, write to the Free Software | |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
23 | * | |
24 | */ | |
25 | ||
26 | package org.postgis.jts; | |
27 | ||
28 | import java.sql.Connection; | |
29 | import java.sql.SQLException; | |
30 | import java.util.Properties; | |
31 | import java.util.logging.Level; | |
32 | import java.util.logging.Logger; | |
33 | ||
34 | import org.postgresql.Driver; | |
35 | import org.postgresql.PGConnection; | |
36 | ||
37 | /** | |
38 | * JtsWrapper | |
39 | * | |
40 | * Wraps the PostGreSQL Driver to add the JTS/PostGIS Object Classes. | |
41 | * | |
42 | * This method currently works with J2EE DataSource implementations, and with | |
43 | * DriverManager framework. | |
44 | * | |
45 | * Simply replace the "jdbc:postgresql:" with a "jdbc:postgres_jts:" in the jdbc | |
46 | * URL. | |
47 | * | |
48 | * When using the drivermanager, you need to initialize JtsWrapper instead of | |
49 | * (or in addition to) org.postgresql.Driver. When using a J2EE DataSource | |
50 | * implementation, set the driver class property in the datasource config, the | |
51 | * following works for jboss: | |
52 | * | |
53 | * <driver-class>org.postgis.jts.PostGisWrapper</driver-class> | |
54 | * | |
55 | * @author markus.schaber@logix-tt.com | |
56 | * | |
57 | */ | |
58 | public class JtsWrapper extends Driver { | |
59 | ||
60 | protected static final Logger logger = Logger.getLogger("org.postgis.DriverWrapper"); | |
61 | ||
62 | private static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; | |
63 | private static final String POSTGIS_PROTOCOL = "jdbc:postgres_jts:"; | |
64 | public static final String REVISION = "$Revision$"; | |
65 | ||
66 | public JtsWrapper() { | |
67 | super(); | |
68 | } | |
69 | ||
70 | static { | |
71 | try { | |
72 | // Try to register ourself to the DriverManager | |
73 | java.sql.DriverManager.registerDriver(new JtsWrapper()); | |
74 | } catch (SQLException e) { | |
75 | logger.log(Level.WARNING, "Error registering PostgreSQL Jts Wrapper Driver", e); | |
76 | } | |
77 | } | |
78 | ||
79 | /** | |
80 | * Creates a postgresql connection, and then adds the JTS GIS data types to | |
81 | * it calling addpgtypes() | |
82 | * | |
83 | * @param url the URL of the database to connect to | |
84 | * @param info a list of arbitrary tag/value pairs as connection arguments | |
85 | * @return a connection to the URL or null if it isnt us | |
86 | * @exception SQLException if a database access error occurs | |
87 | * | |
88 | * @see java.sql.Driver#connect | |
89 | * @see org.postgresql.Driver | |
90 | */ | |
91 | public java.sql.Connection connect(String url, Properties info) throws SQLException { | |
92 | url = mangleURL(url); | |
93 | Connection result = super.connect(url, info); | |
94 | addGISTypes((PGConnection)result); | |
95 | return result; | |
96 | } | |
97 | ||
98 | /** | |
99 | * Adds the JTS/PostGIS Data types to a PG Connection. | |
100 | * @param pgconn The PGConnection object to add the types to | |
101 | * @throws SQLException when an SQLException occurs | |
102 | */ | |
103 | public static void addGISTypes(PGConnection pgconn) throws SQLException { | |
104 | pgconn.addDataType("geometry", org.postgis.jts.JtsGeometry.class); | |
105 | } | |
106 | ||
107 | /** | |
108 | * Mangles the PostGIS URL to return the original PostGreSQL URL | |
109 | * | |
110 | * @param url String containing the url to be "mangled" | |
111 | * @return "mangled" string | |
112 | * @throws SQLException when a SQLException occurs | |
113 | */ | |
114 | public static String mangleURL(String url) throws SQLException { | |
115 | if (url.startsWith(POSTGIS_PROTOCOL)) { | |
116 | return POSTGRES_PROTOCOL + url.substring(POSTGIS_PROTOCOL.length()); | |
117 | } else { | |
118 | throw new SQLException("Unknown protocol or subprotocol in url " + url); | |
119 | } | |
120 | } | |
121 | ||
122 | /** | |
123 | * Check whether the driver thinks he can handle the given URL. | |
124 | * | |
125 | * @see java.sql.Driver#acceptsURL | |
126 | * @param url the URL of the driver | |
127 | * @return true if this driver accepts the given URL | |
128 | */ | |
129 | public boolean acceptsURL(String url) { | |
130 | try { | |
131 | url = mangleURL(url); | |
132 | } catch (SQLException e) { | |
133 | return false; | |
134 | } | |
135 | return super.acceptsURL(url); | |
136 | } | |
137 | ||
138 | /** | |
139 | * Gets the underlying drivers major version number | |
140 | * | |
141 | * @return the drivers major version number | |
142 | */ | |
143 | ||
144 | public int getMajorVersion() { | |
145 | return super.getMajorVersion(); | |
146 | } | |
147 | ||
148 | /** | |
149 | * Get the underlying drivers minor version number | |
150 | * | |
151 | * @return the drivers minor version number | |
152 | */ | |
153 | public int getMinorVersion() { | |
154 | return super.getMinorVersion(); | |
155 | } | |
156 | ||
157 | /** | |
158 | * Returns our own CVS version plus postgres Version | |
159 | * | |
160 | * @return String representation of the version | |
161 | */ | |
162 | public static String getVersion() { | |
163 | return "JtsGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); | |
164 | } | |
165 | } |
0 | <body><p>Parser between JTS and PostGIS geometry formats.</p></body>⏎ |
0 | /* | |
1 | * JtsParserTest.java | |
2 | * | |
3 | * JtsParserTest for JTS - relies on org.postgis V1.0.0+ package. | |
4 | * | |
5 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | * | |
21 | */ | |
22 | ||
23 | package org.postgis.jts; | |
24 | ||
25 | ||
26 | import org.postgis.binary.ValueSetter; | |
27 | ||
28 | import org.locationtech.jts.geom.*; | |
29 | import net.postgis.tools.testutils.TestContainerController; | |
30 | import org.slf4j.Logger; | |
31 | import org.slf4j.LoggerFactory; | |
32 | import org.testng.Assert; | |
33 | import org.testng.ITestContext; | |
34 | import org.testng.annotations.AfterClass; | |
35 | import org.testng.annotations.BeforeClass; | |
36 | import org.testng.annotations.Test; | |
37 | ||
38 | import java.sql.*; | |
39 | ||
40 | ||
41 | /** | |
42 | * JtsParseTest | |
43 | * | |
44 | * This test class was adapted from the {@code JtsTestParsr} example standalone class. | |
45 | * It is meant to be run in standalone mode or run against a PostGIS database, but it will need to be | |
46 | * fixed to run against a PostGIS database as it currently fails in some places with an error: | |
47 | * {@literal function asewkb(geometry) does not exist} | |
48 | */ | |
49 | public class JtsParserTest { | |
50 | ||
51 | private static final Logger logger = LoggerFactory.getLogger(JtsParserTest.class); | |
52 | ||
53 | private static final String JTS_WRAPPER_CLASS_NAME = "org.postgis.jts.JtsWrapper"; | |
54 | ||
55 | /** The srid we use for the srid tests */ | |
56 | public static final int SRID = 4326; | |
57 | ||
58 | /** The string prefix we get for the srid tests */ | |
59 | public static final String SRIDPREFIX = "SRID=" + SRID + ";"; | |
60 | ||
61 | /** | |
62 | * Our set of geometries to test. | |
63 | */ | |
64 | public static final String ALL = "ALL"; | |
65 | public static final String ONLY10 = "ONLY10"; | |
66 | public static final String EQUAL10 = "EQUAL10"; | |
67 | public static final String[][] testset = new String[][] { | |
68 | { ALL, // 2D | |
69 | "POINT(10 10)" }, | |
70 | { ALL, // 3D with 3rd coordinate set to 0 | |
71 | "POINT(10 10 0)" }, | |
72 | { ALL, // 3D | |
73 | "POINT(10 10 20)" }, | |
74 | { ALL, "MULTIPOINT(11 12, 20 20)" }, | |
75 | { ALL, "MULTIPOINT(11 12 13, 20 20 20)" }, | |
76 | { ALL, "LINESTRING(10 10,20 20,50 50,34 34)" }, | |
77 | { ALL, "LINESTRING(10 10 20,20 20 20,50 50 50,34 34 34)" }, | |
78 | { ALL, "POLYGON((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))" }, | |
79 | { ALL, "POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))" }, | |
80 | { | |
81 | ALL, | |
82 | "MULTIPOLYGON(((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)),((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)))" }, | |
83 | { | |
84 | ALL, | |
85 | "MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))" }, | |
86 | { ALL, "MULTILINESTRING((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))" }, | |
87 | { ALL, "MULTILINESTRING((10 10 5,20 10 5,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))" }, | |
88 | { ALL, "GEOMETRYCOLLECTION(POINT(10 10),POINT(20 20))" }, | |
89 | { ALL, "GEOMETRYCOLLECTION(POINT(10 10 20),POINT(20 20 20))" }, | |
90 | { | |
91 | ALL, | |
92 | "GEOMETRYCOLLECTION(LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34))" }, | |
93 | { | |
94 | ALL, | |
95 | "GEOMETRYCOLLECTION(POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))" }, | |
96 | { ONLY10, // Cannot be parsed by 0.X servers | |
97 | "GEOMETRYCOLLECTION(MULTIPOINT(10 10 10, 20 20 20),MULTIPOINT(10 10 10, 20 20 20))" }, | |
98 | { EQUAL10, // PostGIs 0.X "flattens" this geometry, so it is not | |
99 | // equal after reparsing. | |
100 | "GEOMETRYCOLLECTION(MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))" }, | |
101 | { EQUAL10,// PostGIs 0.X "flattens" this geometry, so it is not | |
102 | // equal | |
103 | // after reparsing. | |
104 | "GEOMETRYCOLLECTION(MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))))" }, | |
105 | { | |
106 | ALL, | |
107 | "GEOMETRYCOLLECTION(POINT(10 10 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))" }, | |
108 | { ONLY10, // Collections that contain both X and MultiX do not | |
109 | // work on | |
110 | // PostGIS 0.x | |
111 | "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT(10 10 10, 20 20 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))" }, | |
112 | { ALL,// new (correct) representation | |
113 | "GEOMETRYCOLLECTION EMPTY" }, | |
114 | }; | |
115 | ||
116 | private static JtsBinaryParser jtsBinaryParser = new JtsBinaryParser(); | |
117 | ||
118 | private static final JtsBinaryWriter jtsBinaryWriter = new JtsBinaryWriter(); | |
119 | ||
120 | private Connection connection = null; | |
121 | ||
122 | private Statement statement = null; | |
123 | ||
124 | ||
125 | @Test | |
126 | public void test() throws Exception { | |
127 | for (String[] aTestset : testset) { | |
128 | test(aTestset[1], aTestset[0]); | |
129 | test(SRIDPREFIX + aTestset[1], aTestset[0]); | |
130 | } | |
131 | } | |
132 | ||
133 | ||
134 | public void test(String WKT, String flags) throws SQLException { | |
135 | logger.debug("Original: {}", WKT); | |
136 | Geometry geom = JtsGeometry.geomFromString(WKT); | |
137 | String parsed = geom.toString(); | |
138 | if (WKT.startsWith("SRID=")) { | |
139 | parsed = "SRID=" + geom.getSRID() + ";" + parsed; | |
140 | } | |
141 | logger.debug("Parsed: {}", parsed); | |
142 | Geometry regeom = JtsGeometry.geomFromString(parsed); | |
143 | String reparsed = regeom.toString(); | |
144 | if (WKT.startsWith("SRID=")) { | |
145 | reparsed = "SRID=" + geom.getSRID() + ";" + reparsed; | |
146 | } | |
147 | logger.debug("Re-Parsed: {}", reparsed); | |
148 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
149 | Assert.assertEquals(geom.getSRID(), regeom.getSRID(), "Geometry SRIDs are not equal"); | |
150 | Assert.assertEquals(reparsed, parsed, "Text Reps are not equal"); | |
151 | ||
152 | String hexNWKT = jtsBinaryWriter.writeHexed(geom, ValueSetter.NDR.NUMBER); | |
153 | logger.debug("NDRHex: {}", hexNWKT); | |
154 | regeom = JtsGeometry.geomFromString(hexNWKT); | |
155 | logger.debug("ReNDRHex: {}", regeom); | |
156 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
157 | ||
158 | String hexXWKT = jtsBinaryWriter.writeHexed(geom, ValueSetter.XDR.NUMBER); | |
159 | logger.debug("XDRHex: {}", hexXWKT); | |
160 | regeom = JtsGeometry.geomFromString(hexXWKT); | |
161 | logger.debug("ReXDRHex: {}", regeom); | |
162 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
163 | ||
164 | byte[] NWKT = jtsBinaryWriter.writeBinary(geom, ValueSetter.NDR.NUMBER); | |
165 | regeom = jtsBinaryParser.parse(NWKT); | |
166 | logger.debug("NDR: {}", regeom); | |
167 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
168 | ||
169 | byte[] XWKT = jtsBinaryWriter.writeBinary(geom, ValueSetter.XDR.NUMBER); | |
170 | regeom = jtsBinaryParser.parse(XWKT); | |
171 | logger.debug("XDR: {}", regeom); | |
172 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
173 | ||
174 | Geometry coordArrayGeom = rebuildCS(geom); | |
175 | logger.debug("CoordArray: {}", regeom); | |
176 | Assert.assertEquals(geom, coordArrayGeom, "Geometries are not equal"); | |
177 | ||
178 | String coordArrayWKT = jtsBinaryWriter.writeHexed(coordArrayGeom, ValueSetter.NDR.NUMBER); | |
179 | logger.debug("HexCArray: {}", coordArrayWKT); | |
180 | Assert.assertEquals(coordArrayWKT, hexNWKT, "CoordArray HexWKT is not equal"); | |
181 | ||
182 | int serverPostgisMajor = getPostgisMajor(); | |
183 | ||
184 | if ((flags.equals(ONLY10)) && serverPostgisMajor < 1) { | |
185 | logger.info("PostGIS server too old, skipping test on connection {}", connection.getCatalog()); | |
186 | } else { | |
187 | logger.debug("Testing on connection {}", connection.getCatalog()); | |
188 | ||
189 | Geometry sqlGeom = viaSQL(WKT, statement); | |
190 | logger.debug("SQLin: {}", sqlGeom.toString()); | |
191 | if (!geom.equalsExact(sqlGeom)) { | |
192 | logger.warn("Geometries after SQL are not equal"); | |
193 | if (flags.equals(EQUAL10) && serverPostgisMajor < 1) { | |
194 | logger.info("This is expected with PostGIS {}.X", serverPostgisMajor); | |
195 | } else { | |
196 | Assert.fail(); | |
197 | } | |
198 | } | |
199 | ||
200 | Geometry sqlreGeom = viaSQL(parsed, statement); | |
201 | logger.debug("SQLout: {}", sqlreGeom); | |
202 | if (!geom.equalsExact(sqlreGeom)) { | |
203 | logger.warn("Reparsed Geometries after SQL are not equal"); | |
204 | if (flags.equals(EQUAL10) && serverPostgisMajor < 1) { | |
205 | logger.info("This is expected with PostGIS {}.X", serverPostgisMajor); | |
206 | } else { | |
207 | Assert.fail(); | |
208 | } | |
209 | } | |
210 | ||
211 | sqlreGeom = viaPrepSQL(geom, connection); | |
212 | logger.debug("Prepared: {}", sqlreGeom); | |
213 | if (!geom.equalsExact(sqlreGeom)) { | |
214 | logger.debug("Reparsed Geometries after prepared StatementSQL are not equal"); | |
215 | if (flags.equals(EQUAL10) && serverPostgisMajor < 1) { | |
216 | logger.info("This is expected with PostGIS {}.X", serverPostgisMajor); | |
217 | } else { | |
218 | Assert.fail(); | |
219 | } | |
220 | } | |
221 | ||
222 | // asEWKT() function is not present on PostGIS 0.X, and the test | |
223 | // is pointless as 0.X uses EWKT as canonical rep so the same | |
224 | // functionality was already tested above. | |
225 | if (serverPostgisMajor >= 1) { | |
226 | sqlGeom = ewktViaSQL(WKT, statement); | |
227 | logger.debug("asEWKT: {}", sqlGeom); | |
228 | Assert.assertEquals(geom, sqlGeom); | |
229 | ||
230 | sqlGeom = ewkbViaSQL(WKT, statement); | |
231 | logger.debug("asEWKB: {}", sqlGeom); | |
232 | Assert.assertEquals(geom, sqlGeom); | |
233 | ||
234 | sqlGeom = viaSQL(hexNWKT, statement); | |
235 | logger.debug("hexNWKT: {}", sqlGeom); | |
236 | Assert.assertEquals(geom, sqlGeom); | |
237 | ||
238 | sqlGeom = viaSQL(hexXWKT, statement); | |
239 | logger.debug("hexXWKT: {}", sqlGeom); | |
240 | Assert.assertEquals(geom, sqlGeom); | |
241 | ||
242 | sqlGeom = binaryViaSQL(NWKT, connection); | |
243 | logger.debug("NWKT: {}", sqlGeom); | |
244 | Assert.assertEquals(geom, sqlGeom); | |
245 | ||
246 | sqlGeom = binaryViaSQL(XWKT, connection); | |
247 | logger.debug("XWKT: {}", sqlGeom); | |
248 | Assert.assertEquals(geom, sqlGeom); | |
249 | } | |
250 | } | |
251 | } | |
252 | ||
253 | ||
254 | /** Pass a geometry representation through the SQL server */ | |
255 | private static Geometry viaSQL(String rep, Statement stat) throws SQLException { | |
256 | ResultSet rs = stat.executeQuery("SELECT geometry_in('" + rep + "')"); | |
257 | rs.next(); | |
258 | return ((JtsGeometry) rs.getObject(1)).getGeometry(); | |
259 | } | |
260 | ||
261 | ||
262 | /** | |
263 | * Pass a geometry representation through the SQL server via prepared | |
264 | * statement | |
265 | */ | |
266 | private static Geometry viaPrepSQL(Geometry geom, Connection conn) throws SQLException { | |
267 | PreparedStatement prep = conn.prepareStatement("SELECT ?::geometry"); | |
268 | JtsGeometry wrapper = new JtsGeometry(geom); | |
269 | prep.setObject(1, wrapper, Types.OTHER); | |
270 | ResultSet rs = prep.executeQuery(); | |
271 | rs.next(); | |
272 | JtsGeometry resultwrapper = ((JtsGeometry) rs.getObject(1)); | |
273 | return resultwrapper.getGeometry(); | |
274 | } | |
275 | ||
276 | ||
277 | /** Pass a geometry representation through the SQL server via EWKT */ | |
278 | private static Geometry ewktViaSQL(String rep, Statement stat) throws SQLException { | |
279 | ResultSet rs = stat.executeQuery("SELECT ST_AsEWKT(geometry_in('" + rep + "'))"); | |
280 | rs.next(); | |
281 | String resrep = rs.getString(1); | |
282 | return JtsGeometry.geomFromString(resrep); | |
283 | } | |
284 | ||
285 | ||
286 | /** Pass a geometry representation through the SQL server via EWKB */ | |
287 | private static Geometry ewkbViaSQL(String rep, Statement stat) throws SQLException { | |
288 | ResultSet rs = stat.executeQuery("SELECT ST_AsEWKB(geometry_in('" + rep + "'))"); | |
289 | rs.next(); | |
290 | byte[] resrep = rs.getBytes(1); | |
291 | return jtsBinaryParser.parse(resrep); | |
292 | } | |
293 | ||
294 | ||
295 | /** Pass a EWKB geometry representation through the server */ | |
296 | private static Geometry binaryViaSQL(byte[] rep, Connection conn) throws SQLException { | |
297 | PreparedStatement prep = conn.prepareStatement("SELECT ?::bytea::geometry"); | |
298 | prep.setBytes(1, rep); | |
299 | ResultSet rs = prep.executeQuery(); | |
300 | rs.next(); | |
301 | JtsGeometry resultwrapper = ((JtsGeometry) rs.getObject(1)); | |
302 | return resultwrapper.getGeometry(); | |
303 | } | |
304 | ||
305 | ||
306 | // Rebuild given Geometry with a CoordinateArraySequence implementation. | |
307 | public static Geometry rebuildCS(Geometry geom) { | |
308 | if (geom instanceof Point) { | |
309 | return rebuildCSPoint((Point)geom); | |
310 | } else if (geom instanceof MultiPoint) { | |
311 | return rebuildCSMP((MultiPoint)geom); | |
312 | } else if (geom instanceof LineString) { | |
313 | return rebuildCSLS((LineString)geom); | |
314 | } else if (geom instanceof MultiLineString) { | |
315 | return rebuildCSMLS((MultiLineString)geom); | |
316 | } else if (geom instanceof Polygon) { | |
317 | return rebuildCSP((Polygon)geom); | |
318 | } else if (geom instanceof MultiPolygon) { | |
319 | return rebuildCSMP((MultiPolygon)geom); | |
320 | } else if (geom instanceof GeometryCollection) { | |
321 | return rebuildCSGC((GeometryCollection)geom); | |
322 | } else { | |
323 | throw new AssertionError(); | |
324 | } | |
325 | } | |
326 | ||
327 | ||
328 | private static Point rebuildCSPoint(Point point) { | |
329 | Point result = point.getFactory().createPoint(point.getCoordinate()); | |
330 | result.setSRID(point.getSRID()); | |
331 | return result; | |
332 | } | |
333 | ||
334 | ||
335 | private static MultiPoint rebuildCSMP(MultiPoint mp) { | |
336 | Point[] points = new Point[mp.getNumGeometries()]; | |
337 | for (int i=0; i < points.length; i++) { | |
338 | points[i] = rebuildCSPoint((Point) mp.getGeometryN(i)); | |
339 | } | |
340 | MultiPoint result = mp.getFactory().createMultiPoint(points); | |
341 | result.setSRID(mp.getSRID()); | |
342 | return result; | |
343 | } | |
344 | ||
345 | ||
346 | private static MultiPolygon rebuildCSMP(MultiPolygon multipoly) { | |
347 | Polygon[] polygons = new Polygon[multipoly.getNumGeometries()]; | |
348 | for (int i=0; i < polygons.length; i++) { | |
349 | polygons[i] = rebuildCSP((Polygon)multipoly.getGeometryN(i)); | |
350 | } | |
351 | MultiPolygon result = multipoly.getFactory().createMultiPolygon(polygons); | |
352 | result.setSRID(multipoly.getSRID()); | |
353 | return result; | |
354 | } | |
355 | ||
356 | ||
357 | private static LineString rebuildCSLS(LineString line) { | |
358 | LineString result = line.getFactory().createLineString(line.getCoordinates()); | |
359 | result.setSRID(line.getSRID()); | |
360 | return result; | |
361 | } | |
362 | ||
363 | ||
364 | private static MultiLineString rebuildCSMLS(MultiLineString multiline) { | |
365 | LineString[] polygons = new LineString[multiline.getNumGeometries()]; | |
366 | for (int i=0; i < polygons.length; i++) { | |
367 | polygons[i] = rebuildCSLS((LineString)multiline.getGeometryN(i)); | |
368 | } | |
369 | MultiLineString result = multiline.getFactory().createMultiLineString(polygons); | |
370 | result.setSRID(multiline.getSRID()); | |
371 | return result; | |
372 | ||
373 | } | |
374 | ||
375 | ||
376 | private static Polygon rebuildCSP(Polygon polygon) { | |
377 | LinearRing outer = rebuildLR(polygon.getExteriorRing()); | |
378 | LinearRing[] holes = new LinearRing[polygon.getNumInteriorRing()]; | |
379 | for (int i=0; i < holes.length; i++) { | |
380 | holes[i] = rebuildLR(polygon.getInteriorRingN(i)); | |
381 | } | |
382 | Polygon result = polygon.getFactory().createPolygon(outer, holes); | |
383 | result.setSRID(polygon.getSRID()); | |
384 | return result; | |
385 | } | |
386 | ||
387 | ||
388 | private static LinearRing rebuildLR(LineString ring) { | |
389 | LinearRing result = ring.getFactory().createLinearRing(ring.getCoordinates()); | |
390 | result.setSRID(ring.getSRID()); | |
391 | return result; | |
392 | } | |
393 | ||
394 | ||
395 | private static Geometry rebuildCSGC(GeometryCollection coll) { | |
396 | Geometry[] geoms = new Geometry[coll.getNumGeometries()]; | |
397 | for (int i = 0; i < coll.getNumGeometries(); i++) { | |
398 | geoms[i] = rebuildCS(coll.getGeometryN(i)); | |
399 | } | |
400 | Geometry result = coll.getFactory().createGeometryCollection(geoms); | |
401 | result.setSRID(coll.getSRID()); | |
402 | return result; | |
403 | } | |
404 | ||
405 | ||
406 | public int getPostgisMajor() throws SQLException { | |
407 | ResultSet resultSet = statement.executeQuery("SELECT postgis_version()"); | |
408 | resultSet.next(); | |
409 | String version = resultSet.getString(1); | |
410 | if (version == null) { | |
411 | throw new SQLException("postgis_version returned NULL!"); | |
412 | } | |
413 | version = version.trim(); | |
414 | int idx = version.indexOf('.'); | |
415 | return Integer.parseInt(version.substring(0, idx)); | |
416 | } | |
417 | ||
418 | ||
419 | @BeforeClass | |
420 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
421 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
422 | Assert.assertNotNull(jdbcUrlSuffix); | |
423 | final String jdbcUrl = "jdbc:postgres_jts" + jdbcUrlSuffix; | |
424 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
425 | Assert.assertNotNull(jdbcUsername); | |
426 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
427 | Assert.assertNotNull(jdbcPassword); | |
428 | Class.forName(JTS_WRAPPER_CLASS_NAME); | |
429 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
430 | statement = connection.createStatement(); | |
431 | } | |
432 | ||
433 | ||
434 | @AfterClass | |
435 | public void unallocateDatabaseResources() throws Exception { | |
436 | if ((statement != null) && (!statement.isClosed())) { | |
437 | statement.close(); | |
438 | } | |
439 | if ((connection != null) && (!connection.isClosed())) { | |
440 | connection.close(); | |
441 | } | |
442 | } | |
443 | ||
444 | ||
445 | }⏎ |
0 | <configuration debug="false"> | |
1 | ||
2 | <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | |
3 | <layout class="ch.qos.logback.classic.PatternLayout"> | |
4 | <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> | |
5 | </layout> | |
6 | </appender> | |
7 | ||
8 | <root level="debug"> | |
9 | <appender-ref ref="STDOUT" /> | |
10 | </root> | |
11 | ||
12 | <logger name="com.github.dockerjava" level="ERROR"/> | |
13 | <logger name="org.testcontainers" level="ERROR"/> | |
14 | <logger name="net.postgis" level="ERROR"/> | |
15 | ||
16 | <logger name="org.postgis.jts" level="ERROR"/> | |
17 | ||
18 | </configuration>⏎ |
0 | <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> | |
1 | <suite name="JTS Parser Integration Test Suite" verbose="1"> | |
2 | ||
3 | <parameter name="test.container.image-name" value="${test.container.image}"/> | |
4 | <parameter name="test.container.port" value="${test.db.port}"/> | |
5 | <parameter name="test.container.env.user" value="${test.db.username}"/> | |
6 | <parameter name="test.container.env.password" value="${test.db.password}"/> | |
7 | <parameter name="test.container.env.db" value="${test.db.name}"/> | |
8 | ||
9 | <test name="JTS Parser Integration Tests"> | |
10 | <classes> | |
11 | <class name="net.postgis.tools.testutils.TestContainerController"/> | |
12 | <class name="org.postgis.jts.JtsParserTest"/> | |
13 | </classes> | |
14 | </test> | |
15 | ||
16 | </suite>⏎ |
8 | 8 | <ignoreVersion type="regex">.*\.jre[6-7]</ignoreVersion> |
9 | 9 | </ignoreVersions> |
10 | 10 | <rules> |
11 | <!-- Pin git-commit-id-plugin version to final release version before V5 until codebase migrates to Java11 --> | |
12 | <rule groupId="pl.project13.maven" artifactId="git-commit-id-plugin"> | |
13 | <ignoreVersions> | |
14 | <ignoreVersion type="regex">4\.9\.9</ignoreVersion> | |
15 | </ignoreVersions> | |
16 | </rule> | |
11 | 17 | <!-- Pin testng version to pre-V7 --> |
12 | <rule groupId="org.testng" artifactId="testng" comparisonMethod="maven"> | |
18 | <rule groupId="org.testng" artifactId="testng"> | |
13 | 19 | <ignoreVersions> |
14 | 20 | <ignoreVersion type="regex">7\..*</ignoreVersion> |
15 | 21 | </ignoreVersions> |
16 | 22 | </rule> |
23 | <!-- Ignore logback version with groovyless suffix --> | |
24 | <rule groupId="ch.qos.logback"> | |
25 | <ignoreVersions> | |
26 | <ignoreVersion type="regex">.*-groovyless</ignoreVersion> | |
27 | </ignoreVersions> | |
28 | </rule> | |
17 | 29 | </rules> |
18 | 30 | </ruleset> |
0 | <ruleset xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" | |
1 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
2 | xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd" | |
3 | name="PMD Ruleset" | |
4 | > | |
5 | <description> | |
6 | This ruleset is adapted from the default maven PMD plugin ruleset which can be found here: | |
7 | https://gitbox.apache.org/repos/asf?p=maven-pmd-plugin.git;a=blob_plain;f=src/main/resources/rulesets/java/maven-pmd-plugin-default.xml;hb=HEAD | |
8 | It contains the rules of the old (pre PMD 6.0.0) rulesets java-basic, java-empty, java-imports, | |
9 | java-unnecessary, java-unusedcode. (see https://pmd.github.io/latest/pmd_userdocs_making_rulesets.html) | |
10 | </description> | |
11 | <rule ref="category/java/bestpractices.xml/AvoidUsingHardCodedIP"/> | |
12 | <rule ref="category/java/bestpractices.xml/CheckResultSet"/> | |
13 | <rule ref="category/java/bestpractices.xml/UnusedFormalParameter"/> | |
14 | <rule ref="category/java/bestpractices.xml/UnusedLocalVariable"/> | |
15 | <rule ref="category/java/bestpractices.xml/UnusedPrivateField"/> | |
16 | <rule ref="category/java/bestpractices.xml/UnusedPrivateMethod"/> | |
17 | <rule ref="category/java/codestyle.xml/ExtendsObject"/> | |
18 | <rule ref="category/java/codestyle.xml/ForLoopShouldBeWhileLoop"/> | |
19 | <rule ref="category/java/codestyle.xml/TooManyStaticImports"/> | |
20 | <rule ref="category/java/codestyle.xml/UnnecessaryFullyQualifiedName"/> | |
21 | <rule ref="category/java/codestyle.xml/UnnecessaryImport"/> | |
22 | <rule ref="category/java/codestyle.xml/UnnecessaryModifier"/> | |
23 | <rule ref="category/java/codestyle.xml/UnnecessaryReturn"/> | |
24 | <rule ref="category/java/codestyle.xml/UselessParentheses"/> | |
25 | <rule ref="category/java/codestyle.xml/UselessQualifiedThis"/> | |
26 | <rule ref="category/java/design.xml/CollapsibleIfStatements"/> | |
27 | <rule ref="category/java/design.xml/SimplifiedTernary"/> | |
28 | <rule ref="category/java/design.xml/UselessOverridingMethod"/> | |
29 | <rule ref="category/java/errorprone.xml/AvoidBranchingStatementAsLastInLoop"/> | |
30 | <rule ref="category/java/errorprone.xml/AvoidDecimalLiteralsInBigDecimalConstructor"/> | |
31 | <rule ref="category/java/errorprone.xml/AvoidMultipleUnaryOperators"/> | |
32 | <rule ref="category/java/errorprone.xml/AvoidUsingOctalValues"/> | |
33 | <rule ref="category/java/errorprone.xml/BrokenNullCheck"/> | |
34 | <rule ref="category/java/errorprone.xml/CheckSkipResult"/> | |
35 | <rule ref="category/java/errorprone.xml/ClassCastExceptionWithToArray"/> | |
36 | <rule ref="category/java/errorprone.xml/DontUseFloatTypeForLoopIndices"/> | |
37 | <rule ref="category/java/errorprone.xml/EmptyCatchBlock"/> | |
38 | <rule ref="category/java/errorprone.xml/EmptyFinallyBlock"/> | |
39 | <rule ref="category/java/errorprone.xml/EmptyIfStmt"/> | |
40 | <rule ref="category/java/errorprone.xml/EmptyInitializer"/> | |
41 | <rule ref="category/java/errorprone.xml/EmptyStatementBlock"/> | |
42 | <rule ref="category/java/errorprone.xml/EmptyStatementNotInLoop"/> | |
43 | <rule ref="category/java/errorprone.xml/EmptySwitchStatements"/> | |
44 | <rule ref="category/java/errorprone.xml/EmptySynchronizedBlock"/> | |
45 | <rule ref="category/java/errorprone.xml/EmptyTryBlock"/> | |
46 | <rule ref="category/java/errorprone.xml/EmptyWhileStmt"/> | |
47 | <rule ref="category/java/errorprone.xml/JumbledIncrementer"/> | |
48 | <rule ref="category/java/errorprone.xml/MisplacedNullCheck"/> | |
49 | <rule ref="category/java/errorprone.xml/OverrideBothEqualsAndHashcode"/> | |
50 | <rule ref="category/java/errorprone.xml/ReturnFromFinallyBlock"/> | |
51 | <rule ref="category/java/errorprone.xml/UnconditionalIfStatement"/> | |
52 | <rule ref="category/java/errorprone.xml/UnnecessaryConversionTemporary"/> | |
53 | <rule ref="category/java/errorprone.xml/UnusedNullCheckInEquals"/> | |
54 | <rule ref="category/java/errorprone.xml/UselessOperationOnImmutable"/> | |
55 | <rule ref="category/java/multithreading.xml/AvoidThreadGroup"/> | |
56 | <rule ref="category/java/multithreading.xml/DontCallThreadRun"/> | |
57 | <rule ref="category/java/multithreading.xml/DoubleCheckedLocking"/> | |
58 | <rule ref="category/java/performance.xml/BigIntegerInstantiation"/> | |
59 | <rule ref="category/java/performance.xml/BooleanInstantiation"/> | |
60 | </ruleset>⏎ |
3 | 3 | |
4 | 4 | <groupId>net.postgis</groupId> |
5 | 5 | <artifactId>postgis-java-aggregator</artifactId> |
6 | <version>2.5.0</version> | |
6 | <version>2021.1.0</version> | |
7 | 7 | <packaging>pom</packaging> |
8 | 8 | |
9 | 9 | <name>PostGIS Java Project</name> |
67 | 67 | </mailingLists> |
68 | 68 | |
69 | 69 | <modules> |
70 | <module>postgis-jdbc</module> | |
71 | <module>postgis-jdbc-geometry</module> | |
72 | <module>postgis-jdbc-java2d</module> | |
73 | <module>postgis-jdbc-jts</module> | |
70 | 74 | <module>tools</module> |
71 | <module>postgis-geometry</module> | |
72 | <module>jdbc</module> | |
73 | <module>jdbc_jtsparser</module> | |
74 | <module>postgis-jdbc-java2d</module> | |
75 | 75 | </modules> |
76 | 76 | |
77 | 77 | <scm> |
78 | 78 | <url>https://github.com/postgis/postgis-java</url> |
79 | 79 | <connection>scm:git:git://github.com/postgis/postgis-java.git</connection> |
80 | 80 | <developerConnection>scm:git:git@github.com:postgis/postgis-java.git</developerConnection> |
81 | <tag>postgis-java-aggregator-2.5.0</tag> | |
81 | <tag>postgis-java-aggregator-2021.1.0</tag> | |
82 | 82 | </scm> |
83 | 83 | <issueManagement> |
84 | 84 | <system>GitHub Issues</system> |
85 | 85 | <url>https://github.com/postgis/postgis-java/issues</url> |
86 | 86 | </issueManagement> |
87 | 87 | <distributionManagement> |
88 | <snapshotRepository> | |
89 | <id>ossrh</id> | |
90 | <url>https://oss.sonatype.org/content/repositories/snapshots</url> | |
91 | </snapshotRepository> | |
92 | <repository> | |
93 | <id>ossrh</id> | |
94 | <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> | |
95 | </repository> | |
88 | <site> | |
89 | <id>local-staging-site</id> | |
90 | <url>http://local-staging/</url> | |
91 | </site> | |
96 | 92 | </distributionManagement> |
97 | 93 | |
98 | 94 | <properties> |
99 | <checkstyle.skip>true</checkstyle.skip> | |
100 | 95 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
101 | 96 | <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> |
102 | <java.min.version>1.8</java.min.version> | |
97 | <java.min.version>8</java.min.version> | |
103 | 98 | <maven.min.version>3.6</maven.min.version> |
104 | 99 | <maven.test.skip>false</maven.test.skip> |
105 | <surefire.forkCount>1</surefire.forkCount> | |
106 | <surefire.useSystemClassLoader>true</surefire.useSystemClassLoader> | |
107 | 100 | <maven.integration.test.skip>false</maven.integration.test.skip> |
108 | 101 | <failsafe.forkCount>1</failsafe.forkCount> |
109 | 102 | <failsafe.useSystemClassLoader>true</failsafe.useSystemClassLoader> |
110 | <test.container.image>postgis/postgis:12-3.0-alpine</test.container.image> | |
103 | <surefire.forkCount>1</surefire.forkCount> | |
104 | <surefire.useSystemClassLoader>true</surefire.useSystemClassLoader> | |
105 | <javadoc.path>${java.home}/bin/javadoc</javadoc.path> | |
106 | <checkstyle.skip>true</checkstyle.skip> | |
107 | <cpd.skip>true</cpd.skip> | |
108 | <jxr.skip>false</jxr.skip> | |
109 | <pmd.skip>true</pmd.skip> | |
110 | <spotbugs.skip>true</spotbugs.skip> | |
111 | <test.container.image>postgis/postgis:13-3.1-alpine</test.container.image> | |
111 | 112 | <test.db.username>postgis1</test.db.username> |
112 | 113 | <test.db.password>postgis1</test.db.password> |
113 | 114 | <test.db.name>postgis1</test.db.name> |
114 | 115 | <test.db.port>5432</test.db.port> |
115 | 116 | <!-- Plugin versioning --> |
116 | <build-helper-maven-plugin.version>3.1.0</build-helper-maven-plugin.version> | |
117 | <build-helper-maven-plugin.version>3.2.0</build-helper-maven-plugin.version> | |
117 | 118 | <directory-maven-plugin.version>0.3.1</directory-maven-plugin.version> |
118 | <download-maven-plugin.version>1.5.0</download-maven-plugin.version> | |
119 | <exec-maven-plugin.version>1.6.0</exec-maven-plugin.version> | |
120 | <git-commit-id-plugin.version>4.0.0</git-commit-id-plugin.version> | |
121 | <jacoco-maven-plugin.version>0.8.5</jacoco-maven-plugin.version> | |
122 | <maven-archetype-plugin.version>3.1.2</maven-archetype-plugin.version> | |
123 | <maven-checkstyle-plugin.version>3.1.1</maven-checkstyle-plugin.version> | |
119 | <download-maven-plugin.version>1.6.6</download-maven-plugin.version> | |
120 | <exec-maven-plugin.version>3.0.0</exec-maven-plugin.version> | |
121 | <git-commit-id-plugin.version>4.0.5</git-commit-id-plugin.version> | |
122 | <jacoco-maven-plugin.version>0.8.7</jacoco-maven-plugin.version> | |
123 | <maven-antrun-plugin.version>3.0.0</maven-antrun-plugin.version> | |
124 | <maven-archetype-plugin.version>3.2.0</maven-archetype-plugin.version> | |
125 | <maven-assembly-plugin.version>3.3.0</maven-assembly-plugin.version> | |
126 | <maven-checkstyle-plugin.version>3.1.2</maven-checkstyle-plugin.version> | |
124 | 127 | <maven-clean-plugin.version>3.1.0</maven-clean-plugin.version> |
125 | 128 | <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version> |
126 | <maven-dependency-plugin.version>3.1.2</maven-dependency-plugin.version> | |
129 | <maven-dependency-plugin.version>3.2.0</maven-dependency-plugin.version> | |
127 | 130 | <maven-deploy-plugin.version>2.8.2</maven-deploy-plugin.version> |
128 | <maven-ear-plugin.version>3.0.2</maven-ear-plugin.version> | |
131 | <maven-ear-plugin.version>3.2.0</maven-ear-plugin.version> | |
129 | 132 | <maven-ejb-plugin.version>3.0.1</maven-ejb-plugin.version> |
130 | <maven-enforcer-plugin.version>1.4.1</maven-enforcer-plugin.version> | |
133 | <maven-enforcer-plugin.version>3.0.0</maven-enforcer-plugin.version> | |
131 | 134 | <maven-failsafe-plugin.version>2.22.2</maven-failsafe-plugin.version> |
132 | <maven-gpg-plugin.version>1.6</maven-gpg-plugin.version> | |
135 | <maven-gpg-plugin.version>3.0.1</maven-gpg-plugin.version> | |
133 | 136 | <maven-install-plugin.version>2.5.2</maven-install-plugin.version> |
134 | 137 | <maven-jar-plugin.version>3.2.0</maven-jar-plugin.version> |
135 | 138 | <maven-jarsigner-plugin.version>3.0.0</maven-jarsigner-plugin.version> |
136 | <maven-javadoc-plugin.version>3.2.0</maven-javadoc-plugin.version> | |
137 | <maven-jxr-plugin.version>3.0.0</maven-jxr-plugin.version> | |
139 | <maven-javadoc-plugin.version>3.3.0</maven-javadoc-plugin.version> | |
140 | <maven-jxr-plugin.version>3.1.1</maven-jxr-plugin.version> | |
141 | <maven-pmd-plugin.version>3.14.0</maven-pmd-plugin.version> | |
142 | <maven-project-info-reports-plugin.version>3.1.2</maven-project-info-reports-plugin.version> | |
138 | 143 | <maven-release-plugin.version>2.5.3</maven-release-plugin.version> |
139 | <maven-resources-plugin.version>3.1.0</maven-resources-plugin.version> | |
140 | <maven-site-plugin.version>3.9.0</maven-site-plugin.version> | |
141 | <maven-shade-plugin.version>3.2.2</maven-shade-plugin.version> | |
144 | <maven-resources-plugin.version>3.2.0</maven-resources-plugin.version> | |
145 | <maven-shade-plugin.version>3.2.4</maven-shade-plugin.version> | |
146 | <maven-site-plugin.version>3.9.1</maven-site-plugin.version> | |
142 | 147 | <maven-source-plugin.version>3.2.1</maven-source-plugin.version> |
143 | 148 | <maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version> |
144 | <maven-war-plugin.version>3.2.3</maven-war-plugin.version> | |
145 | <versions-maven-plugin.version>2.7</versions-maven-plugin.version> | |
149 | <maven-surefire-report-plugin.version>2.22.2</maven-surefire-report-plugin.version> | |
150 | <maven-war-plugin.version>3.3.1</maven-war-plugin.version> | |
151 | <spotbugs-maven-plugin.version>4.3.0</spotbugs-maven-plugin.version> | |
152 | <versions-maven-plugin.version>2.8.1</versions-maven-plugin.version> | |
146 | 153 | <!-- Dependency versions --> |
147 | <dependency.checkstyle.version>8.31</dependency.checkstyle.version> | |
148 | <dependency.jts-version.version>1.16.1</dependency.jts-version.version> | |
149 | <dependency.logback.version>1.2.3</dependency.logback.version> | |
150 | <dependency.postgresql-jdbc.version>42.2.11</dependency.postgresql-jdbc.version> | |
151 | <dependency.slfj.version>1.7.30</dependency.slfj.version> | |
152 | <dependency.spatial4j.version>0.7</dependency.spatial4j.version> | |
153 | <dependency.testcontainers.version>1.13.0</dependency.testcontainers.version> | |
154 | <dependency.checkstyle.version>8.45</dependency.checkstyle.version> | |
155 | <dependency.jts-version.version>1.18.1</dependency.jts-version.version> | |
156 | <dependency.logback.version>1.2.5</dependency.logback.version> | |
157 | <dependency.pmd.version>6.37.0</dependency.pmd.version> | |
158 | <dependency.postgresql-jdbc.version>42.2.23</dependency.postgresql-jdbc.version> | |
159 | <dependency.slf4j.version>1.7.32</dependency.slf4j.version> | |
160 | <dependency.spatial4j.version>0.8</dependency.spatial4j.version> | |
161 | <dependency.spotbugs.version>4.3.0</dependency.spotbugs.version> | |
162 | <dependency.testcontainers.version>1.16.0</dependency.testcontainers.version> | |
154 | 163 | <dependency.testng.version>6.14.3</dependency.testng.version> |
155 | 164 | </properties> |
156 | 165 | |
167 | 176 | </dependencyManagement> |
168 | 177 | |
169 | 178 | <dependencies> |
170 | <dependency> | |
171 | <groupId>org.slf4j</groupId> | |
172 | <artifactId>slf4j-api</artifactId> | |
173 | <version>${dependency.slfj.version}</version> | |
174 | </dependency> | |
175 | 179 | <dependency> |
176 | 180 | <groupId>ch.qos.logback</groupId> |
177 | 181 | <artifactId>logback-classic</artifactId> |
184 | 188 | <version>${dependency.logback.version}</version> |
185 | 189 | <scope>test</scope> |
186 | 190 | </dependency> |
191 | <dependency> | |
192 | <groupId>org.slf4j</groupId> | |
193 | <artifactId>slf4j-api</artifactId> | |
194 | <version>${dependency.slf4j.version}</version> | |
195 | </dependency> | |
187 | 196 | </dependencies> |
188 | 197 | |
189 | 198 | <build> |
199 | <resources> | |
200 | <resource> | |
201 | <directory>src/main/resources</directory> | |
202 | </resource> | |
203 | <resource> | |
204 | <directory>src/main/resources-filtered</directory> | |
205 | <filtering>true</filtering> | |
206 | </resource> | |
207 | </resources> | |
208 | <testResources> | |
209 | <testResource> | |
210 | <directory>src/test/resources</directory> | |
211 | </testResource> | |
212 | <testResource> | |
213 | <directory>src/test/resources-filtered</directory> | |
214 | <filtering>true</filtering> | |
215 | </testResource> | |
216 | </testResources> | |
190 | 217 | <pluginManagement> |
191 | 218 | <plugins> |
219 | <plugin> | |
220 | <groupId>com.github.spotbugs</groupId> | |
221 | <artifactId>spotbugs-maven-plugin</artifactId> | |
222 | <version>${spotbugs-maven-plugin.version}</version> | |
223 | <dependencies> | |
224 | <dependency> | |
225 | <groupId>com.github.spotbugs</groupId> | |
226 | <artifactId>spotbugs</artifactId> | |
227 | <version>${dependency.spotbugs.version}</version> | |
228 | </dependency> | |
229 | </dependencies> | |
230 | <executions> | |
231 | <execution> | |
232 | <id>spotbugs-check</id> | |
233 | <phase>verify</phase> | |
234 | <goals> | |
235 | <goal>check</goal> | |
236 | </goals> | |
237 | </execution> | |
238 | </executions> | |
239 | <configuration> | |
240 | <skip>${spotbugs.skip}</skip> | |
241 | </configuration> | |
242 | </plugin> | |
243 | <plugin> | |
244 | <groupId>com.googlecode.maven-download-plugin</groupId> | |
245 | <artifactId>download-maven-plugin</artifactId> | |
246 | <version>${download-maven-plugin.version}</version> | |
247 | </plugin> | |
248 | <plugin> | |
249 | <groupId>org.apache.maven.plugins</groupId> | |
250 | <artifactId>maven-antrun-plugin</artifactId> | |
251 | <version>${maven-antrun-plugin.version}</version> | |
252 | </plugin> | |
253 | <plugin> | |
254 | <groupId>org.apache.maven.plugins</groupId> | |
255 | <artifactId>maven-archetype-plugin</artifactId> | |
256 | <version>${maven-archetype-plugin.version}</version> | |
257 | </plugin> | |
258 | <plugin> | |
259 | <groupId>org.apache.maven.plugins</groupId> | |
260 | <artifactId>maven-assembly-plugin</artifactId> | |
261 | <version>${maven-assembly-plugin.version}</version> | |
262 | </plugin> | |
263 | <plugin> | |
264 | <groupId>org.apache.maven.plugins</groupId> | |
265 | <artifactId>maven-checkstyle-plugin</artifactId> | |
266 | <version>${maven-checkstyle-plugin.version}</version> | |
267 | <dependencies> | |
268 | <dependency> | |
269 | <groupId>com.puppycrawl.tools</groupId> | |
270 | <artifactId>checkstyle</artifactId> | |
271 | <version>${dependency.checkstyle.version}</version> | |
272 | </dependency> | |
273 | </dependencies> | |
274 | <executions> | |
275 | <execution> | |
276 | <id>checkstyle</id> | |
277 | <phase>validate</phase> | |
278 | <goals> | |
279 | <goal>check</goal> | |
280 | </goals> | |
281 | </execution> | |
282 | </executions> | |
283 | <configuration> | |
284 | <configLocation>checkstyle.xml</configLocation> | |
285 | <consoleOutput>true</consoleOutput> | |
286 | <skip>${checkstyle.skip}</skip> | |
287 | <violationSeverity>warning</violationSeverity> | |
288 | </configuration> | |
289 | </plugin> | |
290 | <plugin> | |
291 | <groupId>org.apache.maven.plugins</groupId> | |
292 | <artifactId>maven-clean-plugin</artifactId> | |
293 | <version>${maven-clean-plugin.version}</version> | |
294 | </plugin> | |
295 | <plugin> | |
296 | <groupId>org.apache.maven.plugins</groupId> | |
297 | <artifactId>maven-compiler-plugin</artifactId> | |
298 | <version>${maven-compiler-plugin.version}</version> | |
299 | <configuration> | |
300 | <source>${java.min.version}</source> | |
301 | <target>${java.min.version}</target> | |
302 | </configuration> | |
303 | </plugin> | |
304 | <plugin> | |
305 | <groupId>org.apache.maven.plugins</groupId> | |
306 | <artifactId>maven-dependency-plugin</artifactId> | |
307 | <version>${maven-dependency-plugin.version}</version> | |
308 | </plugin> | |
309 | <plugin> | |
310 | <groupId>org.apache.maven.plugins</groupId> | |
311 | <artifactId>maven-deploy-plugin</artifactId> | |
312 | <version>${maven-deploy-plugin.version}</version> | |
313 | </plugin> | |
314 | <plugin> | |
315 | <groupId>org.apache.maven.plugins</groupId> | |
316 | <artifactId>maven-ear-plugin</artifactId> | |
317 | <version>${maven-ear-plugin.version}</version> | |
318 | </plugin> | |
319 | <plugin> | |
320 | <groupId>org.apache.maven.plugins</groupId> | |
321 | <artifactId>maven-enforcer-plugin</artifactId> | |
322 | <version>${maven-enforcer-plugin.version}</version> | |
323 | <executions> | |
324 | <execution> | |
325 | <id>enforce-maven</id> | |
326 | <goals> | |
327 | <goal>enforce</goal> | |
328 | </goals> | |
329 | </execution> | |
330 | </executions> | |
331 | <configuration> | |
332 | <rules> | |
333 | <requireMavenVersion> | |
334 | <version>[${maven.min.version},)</version> | |
335 | </requireMavenVersion> | |
336 | </rules> | |
337 | </configuration> | |
338 | </plugin> | |
339 | <plugin> | |
340 | <groupId>org.apache.maven.plugins</groupId> | |
341 | <artifactId>maven-failsafe-plugin</artifactId> | |
342 | <version>${maven-failsafe-plugin.version}</version> | |
343 | <executions> | |
344 | <execution> | |
345 | <id>integration-tests</id> | |
346 | <goals> | |
347 | <goal>integration-test</goal> | |
348 | <goal>verify</goal> | |
349 | </goals> | |
350 | <configuration> | |
351 | <forkCount>${failsafe.forkCount}</forkCount> | |
352 | <skip>${maven.integration.test.skip}</skip> | |
353 | <suiteXmlFiles> | |
354 | <suiteXmlFile>${project.build.testOutputDirectory}/testng-it.xml</suiteXmlFile> | |
355 | </suiteXmlFiles> | |
356 | <useSystemClassLoader>${failsafe.useSystemClassLoader}</useSystemClassLoader> | |
357 | </configuration> | |
358 | </execution> | |
359 | </executions> | |
360 | </plugin> | |
361 | <plugin> | |
362 | <groupId>org.apache.maven.plugins</groupId> | |
363 | <artifactId>maven-gpg-plugin</artifactId> | |
364 | <version>${maven-gpg-plugin.version}</version> | |
365 | </plugin> | |
366 | <plugin> | |
367 | <groupId>org.apache.maven.plugins</groupId> | |
368 | <artifactId>maven-install-plugin</artifactId> | |
369 | <version>${maven-install-plugin.version}</version> | |
370 | </plugin> | |
371 | <plugin> | |
372 | <groupId>org.apache.maven.plugins</groupId> | |
373 | <artifactId>maven-jar-plugin</artifactId> | |
374 | <version>${maven-jar-plugin.version}</version> | |
375 | </plugin> | |
376 | <plugin> | |
377 | <groupId>org.apache.maven.plugins</groupId> | |
378 | <artifactId>maven-jarsigner-plugin</artifactId> | |
379 | <version>${maven-jarsigner-plugin.version}</version> | |
380 | </plugin> | |
381 | <plugin> | |
382 | <groupId>org.apache.maven.plugins</groupId> | |
383 | <artifactId>maven-javadoc-plugin</artifactId> | |
384 | <version>${maven-javadoc-plugin.version}</version> | |
385 | <configuration> | |
386 | <javadocExecutable>${javadoc.path}</javadocExecutable> | |
387 | <source>${java.min.version}</source> | |
388 | </configuration> | |
389 | </plugin> | |
390 | <plugin> | |
391 | <groupId>org.apache.maven.plugins</groupId> | |
392 | <artifactId>maven-jxr-plugin</artifactId> | |
393 | <version>${maven-jxr-plugin.version}</version> | |
394 | </plugin> | |
395 | <plugin> | |
396 | <groupId>org.apache.maven.plugins</groupId> | |
397 | <artifactId>maven-pmd-plugin</artifactId> | |
398 | <version>${maven-pmd-plugin.version}</version> | |
399 | <dependencies> | |
400 | <dependency> | |
401 | <groupId>net.sourceforge.pmd</groupId> | |
402 | <artifactId>pmd-core</artifactId> | |
403 | <version>${dependency.pmd.version}</version> | |
404 | </dependency> | |
405 | <dependency> | |
406 | <groupId>net.sourceforge.pmd</groupId> | |
407 | <artifactId>pmd-java</artifactId> | |
408 | <version>${dependency.pmd.version}</version> | |
409 | </dependency> | |
410 | <dependency> | |
411 | <groupId>net.sourceforge.pmd</groupId> | |
412 | <artifactId>pmd-javascript</artifactId> | |
413 | <version>${dependency.pmd.version}</version> | |
414 | </dependency> | |
415 | <dependency> | |
416 | <groupId>net.sourceforge.pmd</groupId> | |
417 | <artifactId>pmd-jsp</artifactId> | |
418 | <version>${dependency.pmd.version}</version> | |
419 | </dependency> | |
420 | </dependencies> | |
421 | <executions> | |
422 | <execution> | |
423 | <id>pmd-check</id> | |
424 | <phase>verify</phase> | |
425 | <goals> | |
426 | <goal>check</goal> | |
427 | </goals> | |
428 | <configuration> | |
429 | <skip>${pmd.skip}</skip> | |
430 | </configuration> | |
431 | </execution> | |
432 | <execution> | |
433 | <id>cpd-check</id> | |
434 | <phase>verify</phase> | |
435 | <goals> | |
436 | <goal>cpd-check</goal> | |
437 | </goals> | |
438 | <configuration> | |
439 | <skip>${cpd.skip}</skip> | |
440 | </configuration> | |
441 | </execution> | |
442 | </executions> | |
443 | <configuration> | |
444 | <printFailingErrors>true</printFailingErrors> | |
445 | <rulesets> | |
446 | <!--suppress UnresolvedMavenProperty --> | |
447 | <ruleset>file:///${multi.module.root}/pmd.xml</ruleset> | |
448 | </rulesets> | |
449 | </configuration> | |
450 | </plugin> | |
451 | <plugin> | |
452 | <groupId>org.apache.maven.plugins</groupId> | |
453 | <artifactId>maven-project-info-reports-plugin</artifactId> | |
454 | <version>${maven-project-info-reports-plugin.version}</version> | |
455 | </plugin> | |
456 | <plugin> | |
457 | <groupId>org.apache.maven.plugins</groupId> | |
458 | <artifactId>maven-release-plugin</artifactId> | |
459 | <version>${maven-release-plugin.version}</version> | |
460 | <configuration> | |
461 | <autoVersionSubmodules>true</autoVersionSubmodules> | |
462 | <localCheckout>true</localCheckout> | |
463 | <pushChanges>false</pushChanges> | |
464 | <releaseProfiles>release-sign-artifacts,sonatype-deployment</releaseProfiles> | |
465 | </configuration> | |
466 | </plugin> | |
467 | <plugin> | |
468 | <groupId>org.apache.maven.plugins</groupId> | |
469 | <artifactId>maven-resources-plugin</artifactId> | |
470 | <version>${maven-resources-plugin.version}</version> | |
471 | </plugin> | |
472 | <plugin> | |
473 | <groupId>org.apache.maven.plugins</groupId> | |
474 | <artifactId>maven-shade-plugin</artifactId> | |
475 | <version>${maven-shade-plugin.version}</version> | |
476 | </plugin> | |
477 | <plugin> | |
478 | <groupId>org.apache.maven.plugins</groupId> | |
479 | <artifactId>maven-site-plugin</artifactId> | |
480 | <version>${maven-site-plugin.version}</version> | |
481 | <configuration> | |
482 | <skipDeploy>true</skipDeploy> | |
483 | </configuration> | |
484 | </plugin> | |
485 | <plugin> | |
486 | <groupId>org.apache.maven.plugins</groupId> | |
487 | <artifactId>maven-source-plugin</artifactId> | |
488 | <version>${maven-source-plugin.version}</version> | |
489 | </plugin> | |
490 | <plugin> | |
491 | <groupId>org.apache.maven.plugins</groupId> | |
492 | <artifactId>maven-surefire-plugin</artifactId> | |
493 | <version>${maven-surefire-plugin.version}</version> | |
494 | <configuration> | |
495 | <forkCount>${surefire.forkCount}</forkCount> | |
496 | <skip>${maven.test.skip}</skip> | |
497 | <suiteXmlFiles> | |
498 | <suiteXmlFile>${project.build.testOutputDirectory}/testng.xml</suiteXmlFile> | |
499 | </suiteXmlFiles> | |
500 | <useSystemClassLoader>${surefire.useSystemClassLoader}</useSystemClassLoader> | |
501 | </configuration> | |
502 | </plugin> | |
503 | <plugin> | |
504 | <groupId>org.apache.maven.plugins</groupId> | |
505 | <artifactId>maven-surefire-report-plugin</artifactId> | |
506 | <version>${maven-surefire-report-plugin.version}</version> | |
507 | </plugin> | |
508 | <plugin> | |
509 | <groupId>org.apache.maven.plugins</groupId> | |
510 | <artifactId>maven-war-plugin</artifactId> | |
511 | <version>${maven-war-plugin.version}</version> | |
512 | </plugin> | |
513 | <plugin> | |
514 | <groupId>org.codehaus.mojo</groupId> | |
515 | <artifactId>build-helper-maven-plugin</artifactId> | |
516 | <version>${build-helper-maven-plugin.version}</version> | |
517 | </plugin> | |
518 | <plugin> | |
519 | <groupId>org.codehaus.mojo</groupId> | |
520 | <artifactId>exec-maven-plugin</artifactId> | |
521 | <version>${exec-maven-plugin.version}</version> | |
522 | </plugin> | |
192 | 523 | <plugin> |
193 | 524 | <groupId>org.codehaus.mojo</groupId> |
194 | 525 | <artifactId>versions-maven-plugin</artifactId> |
195 | 526 | <version>${versions-maven-plugin.version}</version> |
527 | <executions> | |
528 | <execution> | |
529 | <id>check-parent-versions-update</id> | |
530 | <goals> | |
531 | <goal>display-parent-updates</goal> | |
532 | </goals> | |
533 | <phase>validate</phase> | |
534 | </execution> | |
535 | </executions> | |
196 | 536 | <configuration> |
197 | <rulesUri>file:///${pom.basedir}/maven-version-rules.xml</rulesUri> | |
537 | <!--suppress UnresolvedMavenProperty --> | |
538 | <rulesUri>file:///${multi.module.root}/maven-version-rules.xml</rulesUri> | |
198 | 539 | </configuration> |
199 | 540 | </plugin> |
200 | 541 | <plugin> |
201 | 542 | <groupId>org.commonjava.maven.plugins</groupId> |
202 | 543 | <artifactId>directory-maven-plugin</artifactId> |
203 | 544 | <version>${directory-maven-plugin.version}</version> |
545 | <executions> | |
546 | <execution> | |
547 | <id>multi-module-root-directory-build</id> | |
548 | <goals> | |
549 | <goal>directory-of</goal> | |
550 | </goals> | |
551 | <phase>validate</phase> | |
552 | <configuration> | |
553 | <property>multi.module.root</property> | |
554 | <project> | |
555 | <groupId>net.postgis</groupId> | |
556 | <artifactId>postgis-java-aggregator</artifactId> | |
557 | </project> | |
558 | </configuration> | |
559 | </execution> | |
560 | <execution> | |
561 | <id>multi-module-root-directory-site</id> | |
562 | <goals> | |
563 | <goal>directory-of</goal> | |
564 | </goals> | |
565 | <phase>pre-site</phase> | |
566 | <configuration> | |
567 | <property>multi.module.root</property> | |
568 | <project> | |
569 | <groupId>net.postgis</groupId> | |
570 | <artifactId>postgis-java-aggregator</artifactId> | |
571 | </project> | |
572 | </configuration> | |
573 | </execution> | |
574 | </executions> | |
575 | </plugin> | |
576 | <plugin> | |
577 | <groupId>org.jacoco</groupId> | |
578 | <artifactId>jacoco-maven-plugin</artifactId> | |
579 | <version>${jacoco-maven-plugin.version}</version> | |
580 | <executions> | |
581 | <execution> | |
582 | <id>pre-unit-test</id> | |
583 | <goals> | |
584 | <goal>prepare-agent</goal> | |
585 | </goals> | |
586 | </execution> | |
587 | <execution> | |
588 | <id>unit-test-report</id> | |
589 | <phase>test</phase> | |
590 | <goals> | |
591 | <goal>report</goal> | |
592 | </goals> | |
593 | </execution> | |
594 | <execution> | |
595 | <id>pre-integration-test</id> | |
596 | <goals> | |
597 | <goal>prepare-agent-integration</goal> | |
598 | </goals> | |
599 | <configuration> | |
600 | <destFile>${project.build.directory}/jacoco-it.exec</destFile> | |
601 | </configuration> | |
602 | </execution> | |
603 | <execution> | |
604 | <id>integration-test-report</id> | |
605 | <phase>integration-test</phase> | |
606 | <goals> | |
607 | <goal>report-integration</goal> | |
608 | </goals> | |
609 | <configuration> | |
610 | <dataFile>${project.build.directory}/jacoco-it.exec</dataFile> | |
611 | <outputDirectory>${project.reporting.outputDirectory}/jacoco-it</outputDirectory> | |
612 | </configuration> | |
613 | </execution> | |
614 | </executions> | |
615 | </plugin> | |
616 | <plugin> | |
617 | <groupId>pl.project13.maven</groupId> | |
618 | <artifactId>git-commit-id-plugin</artifactId> | |
619 | <version>${git-commit-id-plugin.version}</version> | |
620 | <executions> | |
621 | <execution> | |
622 | <id>git-describe</id> | |
623 | <goals> | |
624 | <goal>revision</goal> | |
625 | </goals> | |
626 | <configuration> | |
627 | <generateGitPropertiesFile>true</generateGitPropertiesFile> | |
628 | <generateGitPropertiesFilename>${project.build.outputDirectory}/META-INF/git.properties</generateGitPropertiesFilename> | |
629 | <includeOnlyProperties> | |
630 | <property>git.branch$</property> | |
631 | <!--<property>git.build.host$</property>--> | |
632 | <property>git.build.number$</property> | |
633 | <property>git.build.number.unique$</property> | |
634 | <property>git.build.time$</property> | |
635 | <property>git.build.user.email$</property> | |
636 | <property>git.build.user.name$</property> | |
637 | <property>git.build.version$</property> | |
638 | <property>git.closest.tag.commit.count$</property> | |
639 | <property>git.closest.tag.name$</property> | |
640 | <property>git.commit.id$</property> | |
641 | <property>git.commit.id.abbrev$</property> | |
642 | <property>git.commit.user.email$</property> | |
643 | <property>git.commit.user.name$</property> | |
644 | <property>git.commit.time$</property> | |
645 | <property>git.tags$</property> | |
646 | </includeOnlyProperties> | |
647 | </configuration> | |
648 | </execution> | |
649 | </executions> | |
204 | 650 | </plugin> |
205 | 651 | </plugins> |
206 | 652 | </pluginManagement> |
207 | 653 | <plugins> |
208 | 654 | <plugin> |
209 | <groupId>com.googlecode.maven-download-plugin</groupId> | |
210 | <artifactId>download-maven-plugin</artifactId> | |
211 | <version>${download-maven-plugin.version}</version> | |
212 | </plugin> | |
213 | <plugin> | |
214 | 655 | <groupId>org.apache.maven.plugins</groupId> |
215 | <artifactId>maven-archetype-plugin</artifactId> | |
216 | <version>${maven-archetype-plugin.version}</version> | |
656 | <artifactId>maven-enforcer-plugin</artifactId> | |
657 | </plugin> | |
658 | <plugin> | |
659 | <groupId>org.commonjava.maven.plugins</groupId> | |
660 | <artifactId>directory-maven-plugin</artifactId> | |
661 | </plugin> | |
662 | <plugin> | |
663 | <groupId>com.github.spotbugs</groupId> | |
664 | <artifactId>spotbugs-maven-plugin</artifactId> | |
217 | 665 | </plugin> |
218 | 666 | <plugin> |
219 | 667 | <groupId>org.apache.maven.plugins</groupId> |
220 | 668 | <artifactId>maven-checkstyle-plugin</artifactId> |
221 | <version>${maven-checkstyle-plugin.version}</version> | |
222 | <dependencies> | |
223 | <dependency> | |
224 | <groupId>com.puppycrawl.tools</groupId> | |
225 | <artifactId>checkstyle</artifactId> | |
226 | <version>${dependency.checkstyle.version}</version> | |
227 | </dependency> | |
228 | </dependencies> | |
229 | <configuration> | |
230 | <configLocation>checkstyle.xml</configLocation> | |
231 | <consoleOutput>true</consoleOutput> | |
232 | <skip>${checkstyle.skip}</skip> | |
233 | <!--<suppressionsLocation>suppressions.xml</suppressionsLocation>--> | |
234 | <violationSeverity>warning</violationSeverity> | |
235 | </configuration> | |
236 | 669 | </plugin> |
237 | 670 | <plugin> |
238 | 671 | <groupId>org.apache.maven.plugins</groupId> |
239 | <artifactId>maven-clean-plugin</artifactId> | |
240 | <version>${maven-clean-plugin.version}</version> | |
672 | <artifactId>maven-pmd-plugin</artifactId> | |
241 | 673 | </plugin> |
242 | 674 | <plugin> |
243 | 675 | <groupId>org.apache.maven.plugins</groupId> |
244 | <artifactId>maven-compiler-plugin</artifactId> | |
245 | <version>${maven-compiler-plugin.version}</version> | |
246 | <configuration> | |
247 | <source>${java.min.version}</source> | |
248 | <target>${java.min.version}</target> | |
249 | </configuration> | |
250 | </plugin> | |
251 | <plugin> | |
252 | <groupId>org.apache.maven.plugins</groupId> | |
253 | <artifactId>maven-dependency-plugin</artifactId> | |
254 | <version>${maven-dependency-plugin.version}</version> | |
255 | </plugin> | |
256 | <plugin> | |
257 | <groupId>org.apache.maven.plugins</groupId> | |
258 | <artifactId>maven-deploy-plugin</artifactId> | |
259 | <version>${maven-deploy-plugin.version}</version> | |
260 | </plugin> | |
261 | <plugin> | |
262 | <groupId>org.apache.maven.plugins</groupId> | |
263 | <artifactId>maven-ear-plugin</artifactId> | |
264 | <version>${maven-ear-plugin.version}</version> | |
265 | </plugin> | |
266 | <plugin> | |
267 | <groupId>org.apache.maven.plugins</groupId> | |
268 | <artifactId>maven-enforcer-plugin</artifactId> | |
269 | <version>${maven-enforcer-plugin.version}</version> | |
270 | <executions> | |
271 | <execution> | |
272 | <id>enforce-maven</id> | |
273 | <goals> | |
274 | <goal>enforce</goal> | |
275 | </goals> | |
276 | <configuration> | |
277 | <rules> | |
278 | <requireMavenVersion> | |
279 | <version>[${maven.min.version},)</version> | |
280 | </requireMavenVersion> | |
281 | </rules> | |
282 | </configuration> | |
283 | </execution> | |
284 | </executions> | |
285 | </plugin> | |
286 | <plugin> | |
287 | <groupId>org.apache.maven.plugins</groupId> | |
288 | <artifactId>maven-failsafe-plugin</artifactId> | |
289 | <version>${maven-failsafe-plugin.version}</version> | |
290 | <configuration> | |
291 | <forkCount>${failsafe.forkCount}</forkCount> | |
292 | <skip>${maven.integration.test.skip}</skip> | |
293 | <systemPropertyVariables> | |
294 | <derby.stream.error.file> | |
295 | ${project.build.directory}/derby.log | |
296 | </derby.stream.error.file> | |
297 | </systemPropertyVariables> | |
298 | <useSystemClassLoader>${failsafe.useSystemClassLoader}</useSystemClassLoader> | |
299 | </configuration> | |
300 | </plugin> | |
301 | <plugin> | |
302 | <groupId>org.apache.maven.plugins</groupId> | |
303 | <artifactId>maven-gpg-plugin</artifactId> | |
304 | <version>${maven-gpg-plugin.version}</version> | |
305 | </plugin> | |
306 | <plugin> | |
307 | <groupId>org.apache.maven.plugins</groupId> | |
308 | <artifactId>maven-install-plugin</artifactId> | |
309 | <version>${maven-install-plugin.version}</version> | |
310 | </plugin> | |
311 | <plugin> | |
312 | <groupId>org.apache.maven.plugins</groupId> | |
313 | <artifactId>maven-jar-plugin</artifactId> | |
314 | <version>${maven-jar-plugin.version}</version> | |
315 | </plugin> | |
316 | <plugin> | |
317 | <groupId>org.apache.maven.plugins</groupId> | |
318 | <artifactId>maven-jarsigner-plugin</artifactId> | |
319 | <version>${maven-jarsigner-plugin.version}</version> | |
320 | </plugin> | |
676 | <artifactId>maven-release-plugin</artifactId> | |
677 | </plugin> | |
678 | <plugin> | |
679 | <groupId>org.jacoco</groupId> | |
680 | <artifactId>jacoco-maven-plugin</artifactId> | |
681 | </plugin> | |
682 | <plugin> | |
683 | <groupId>pl.project13.maven</groupId> | |
684 | <artifactId>git-commit-id-plugin</artifactId> | |
685 | </plugin> | |
686 | </plugins> | |
687 | </build> | |
688 | ||
689 | <reporting> | |
690 | <plugins> | |
321 | 691 | <plugin> |
322 | 692 | <groupId>org.apache.maven.plugins</groupId> |
323 | 693 | <artifactId>maven-javadoc-plugin</artifactId> |
324 | <version>${maven-javadoc-plugin.version}</version> | |
325 | <configuration> | |
326 | <source>${java.min.version}</source> | |
327 | </configuration> | |
694 | <reportSets> | |
695 | <reportSet> | |
696 | <id>javadoc-aggregated</id> | |
697 | <inherited>false</inherited> | |
698 | <reports> | |
699 | <report>aggregate</report> | |
700 | <report>test-aggregate</report> | |
701 | </reports> | |
702 | </reportSet> | |
703 | </reportSets> | |
328 | 704 | </plugin> |
329 | 705 | <plugin> |
330 | 706 | <groupId>org.apache.maven.plugins</groupId> |
331 | 707 | <artifactId>maven-jxr-plugin</artifactId> |
332 | <version>${maven-jxr-plugin.version}</version> | |
708 | <reportSets> | |
709 | <reportSet> | |
710 | <id>jxr-aggregated</id> | |
711 | <inherited>false</inherited> | |
712 | <reports> | |
713 | <report>aggregate</report> | |
714 | <report>test-aggregate</report> | |
715 | </reports> | |
716 | </reportSet> | |
717 | </reportSets> | |
718 | </plugin> | |
719 | <plugin> | |
720 | <groupId>com.github.spotbugs</groupId> | |
721 | <artifactId>spotbugs-maven-plugin</artifactId> | |
722 | <reportSets> | |
723 | <reportSet> | |
724 | <id>spotbugs</id> | |
725 | <inherited>true</inherited> | |
726 | <configuration> | |
727 | <skip>false</skip> | |
728 | </configuration> | |
729 | <reports> | |
730 | <report>spotbugs</report> | |
731 | </reports> | |
732 | </reportSet> | |
733 | </reportSets> | |
333 | 734 | </plugin> |
334 | 735 | <plugin> |
335 | 736 | <groupId>org.apache.maven.plugins</groupId> |
336 | <artifactId>maven-release-plugin</artifactId> | |
337 | <version>${maven-release-plugin.version}</version> | |
338 | <configuration> | |
339 | <autoVersionSubmodules>true</autoVersionSubmodules> | |
340 | <localCheckout>true</localCheckout> | |
341 | <pushChanges>false</pushChanges> | |
342 | <releaseProfiles>release-sign-artifacts</releaseProfiles> | |
343 | </configuration> | |
737 | <artifactId>maven-checkstyle-plugin</artifactId> | |
738 | <reportSets> | |
739 | <reportSet> | |
740 | <id>checkstyle-aggregated</id> | |
741 | <inherited>false</inherited> | |
742 | <configuration> | |
743 | <skip>false</skip> | |
744 | </configuration> | |
745 | <reports> | |
746 | <report>checkstyle-aggregate</report> | |
747 | </reports> | |
748 | </reportSet> | |
749 | </reportSets> | |
344 | 750 | </plugin> |
345 | 751 | <plugin> |
346 | 752 | <groupId>org.apache.maven.plugins</groupId> |
347 | <artifactId>maven-resources-plugin</artifactId> | |
348 | <version>${maven-resources-plugin.version}</version> | |
753 | <artifactId>maven-pmd-plugin</artifactId> | |
754 | <reportSets> | |
755 | <reportSet> | |
756 | <id>pmd</id> | |
757 | <inherited>false</inherited> | |
758 | <configuration> | |
759 | <aggregate>true</aggregate> | |
760 | <skip>false</skip> | |
761 | <rulesets> | |
762 | <ruleset>pmd.xml</ruleset> | |
763 | </rulesets> | |
764 | </configuration> | |
765 | <reports> | |
766 | <report>pmd</report> | |
767 | <report>cpd</report> | |
768 | </reports> | |
769 | </reportSet> | |
770 | </reportSets> | |
349 | 771 | </plugin> |
350 | 772 | <plugin> |
351 | 773 | <groupId>org.apache.maven.plugins</groupId> |
352 | <artifactId>maven-site-plugin</artifactId> | |
353 | <version>${maven-site-plugin.version}</version> | |
354 | </plugin> | |
355 | <plugin> | |
356 | <groupId>org.apache.maven.plugins</groupId> | |
357 | <artifactId>maven-shade-plugin</artifactId> | |
358 | <version>${maven-shade-plugin.version}</version> | |
359 | </plugin> | |
360 | <plugin> | |
361 | <groupId>org.apache.maven.plugins</groupId> | |
362 | <artifactId>maven-source-plugin</artifactId> | |
363 | <version>${maven-source-plugin.version}</version> | |
364 | </plugin> | |
365 | <plugin> | |
366 | <groupId>org.apache.maven.plugins</groupId> | |
367 | <artifactId>maven-surefire-plugin</artifactId> | |
368 | <version>${maven-surefire-plugin.version}</version> | |
369 | <configuration> | |
370 | <forkCount>${surefire.forkCount}</forkCount> | |
371 | <skip>${maven.test.skip}</skip> | |
372 | <systemPropertyVariables> | |
373 | <derby.stream.error.file> | |
374 | ${project.build.directory}/derby.log | |
375 | </derby.stream.error.file> | |
376 | </systemPropertyVariables> | |
377 | <useSystemClassLoader>${surefire.useSystemClassLoader}</useSystemClassLoader> | |
378 | </configuration> | |
379 | </plugin> | |
380 | <plugin> | |
381 | <groupId>org.apache.maven.plugins</groupId> | |
382 | <artifactId>maven-war-plugin</artifactId> | |
383 | <version>${maven-war-plugin.version}</version> | |
774 | <artifactId>maven-surefire-report-plugin</artifactId> | |
775 | <reportSets> | |
776 | <reportSet> | |
777 | <id>surefire</id> | |
778 | <reports> | |
779 | <report>report-only</report> | |
780 | <report>failsafe-report-only</report> | |
781 | </reports> | |
782 | </reportSet> | |
783 | </reportSets> | |
384 | 784 | </plugin> |
385 | 785 | <plugin> |
386 | 786 | <groupId>org.codehaus.mojo</groupId> |
387 | <artifactId>build-helper-maven-plugin</artifactId> | |
388 | <version>${build-helper-maven-plugin.version}</version> | |
389 | </plugin> | |
390 | <plugin> | |
391 | <groupId>org.codehaus.mojo</groupId> | |
392 | <artifactId>exec-maven-plugin</artifactId> | |
393 | <version>${exec-maven-plugin.version}</version> | |
787 | <artifactId>versions-maven-plugin</artifactId> | |
788 | <reportSets> | |
789 | <reportSet> | |
790 | <id>version-update-reports</id> | |
791 | <reports> | |
792 | <report>dependency-updates-report</report> | |
793 | <report>plugin-updates-report</report> | |
794 | <report>property-updates-report</report> | |
795 | </reports> | |
796 | </reportSet> | |
797 | </reportSets> | |
394 | 798 | </plugin> |
395 | 799 | <plugin> |
396 | 800 | <groupId>org.jacoco</groupId> |
397 | 801 | <artifactId>jacoco-maven-plugin</artifactId> |
398 | <version>${jacoco-maven-plugin.version}</version> | |
399 | <executions> | |
400 | <execution> | |
401 | <id>pre-unit-test</id> | |
402 | <goals> | |
403 | <goal>prepare-agent</goal> | |
404 | </goals> | |
405 | </execution> | |
406 | <execution> | |
407 | <id>unit-test-report</id> | |
408 | <phase>test</phase> | |
409 | <goals> | |
410 | <goal>report</goal> | |
411 | </goals> | |
412 | </execution> | |
413 | <execution> | |
414 | <id>pre-integration-test</id> | |
415 | <goals> | |
416 | <goal>prepare-agent-integration</goal> | |
417 | </goals> | |
418 | <configuration> | |
419 | <destFile>${project.build.directory}/jacoco-it.exec</destFile> | |
420 | </configuration> | |
421 | </execution> | |
422 | <execution> | |
423 | <id>integration-test-report</id> | |
424 | <phase>integration-test</phase> | |
425 | <goals> | |
426 | <goal>report-integration</goal> | |
427 | </goals> | |
428 | <configuration> | |
429 | <dataFile>${project.build.directory}/jacoco-it.exec</dataFile> | |
430 | <outputDirectory>${project.reporting.outputDirectory}/jacoco-it</outputDirectory> | |
431 | </configuration> | |
432 | </execution> | |
433 | </executions> | |
434 | </plugin> | |
435 | <plugin> | |
436 | <groupId>pl.project13.maven</groupId> | |
437 | <artifactId>git-commit-id-plugin</artifactId> | |
438 | <version>${git-commit-id-plugin.version}</version> | |
439 | <executions> | |
440 | <execution> | |
441 | <id>git-describe</id> | |
442 | <goals> | |
443 | <goal>revision</goal> | |
444 | </goals> | |
445 | <configuration> | |
446 | <generateGitPropertiesFile>true</generateGitPropertiesFile> | |
447 | <generateGitPropertiesFilename>${project.build.outputDirectory}/META-INF/git.properties</generateGitPropertiesFilename> | |
448 | <includeOnlyProperties> | |
449 | <property>git.branch$</property> | |
450 | <!--<property>git.build.host$</property>--> | |
451 | <property>git.build.number$</property> | |
452 | <property>git.build.number.unique$</property> | |
453 | <property>git.build.time$</property> | |
454 | <property>git.build.user.email$</property> | |
455 | <property>git.build.user.name$</property> | |
456 | <property>git.build.version$</property> | |
457 | <property>git.closest.tag.commit.count$</property> | |
458 | <property>git.closest.tag.name$</property> | |
459 | <property>git.commit.id$</property> | |
460 | <property>git.commit.id.abbrev$</property> | |
461 | <property>git.commit.user.email$</property> | |
462 | <property>git.commit.user.name$</property> | |
463 | <property>git.commit.time$</property> | |
464 | <property>git.tags$</property> | |
465 | </includeOnlyProperties> | |
466 | </configuration> | |
467 | </execution> | |
468 | </executions> | |
802 | <reportSets> | |
803 | <reportSet> | |
804 | <id>test-coverage-report</id> | |
805 | <reports> | |
806 | <report>report</report> | |
807 | <report>report-integration</report> | |
808 | <report>report-aggregate</report> | |
809 | </reports> | |
810 | </reportSet> | |
811 | </reportSets> | |
469 | 812 | </plugin> |
470 | 813 | </plugins> |
471 | </build> | |
814 | </reporting> | |
472 | 815 | |
473 | 816 | <profiles> |
817 | <!-- This profile isn't tested on windows, the path may not be specified correctly. --> | |
818 | <profile> | |
819 | <id>windows-javadoc</id> | |
820 | <activation> | |
821 | <os> | |
822 | <family>windows</family> | |
823 | </os> | |
824 | </activation> | |
825 | <properties> | |
826 | <javadoc.path>${java.home}/bin/javadoc.exe</javadoc.path> | |
827 | </properties> | |
828 | </profile> | |
829 | <profile> | |
830 | <id>javahome-env-javadoc</id> | |
831 | <activation> | |
832 | <property> | |
833 | <name>env.JAVA_HOME</name> | |
834 | </property> | |
835 | </activation> | |
836 | <properties> | |
837 | <javadoc.path>${env.JAVA_HOME}/bin/javadoc</javadoc.path> | |
838 | </properties> | |
839 | </profile> | |
474 | 840 | <profile> |
475 | 841 | <id>check-versions</id> |
476 | 842 | <build> |
477 | 843 | <plugins> |
478 | <plugin> | |
479 | <groupId>org.commonjava.maven.plugins</groupId> | |
480 | <artifactId>directory-maven-plugin</artifactId> | |
481 | <executions> | |
482 | <execution> | |
483 | <id>directory-of-property</id> | |
484 | <goals> | |
485 | <goal>directory-of</goal> | |
486 | </goals> | |
487 | <phase>validate</phase> | |
488 | <configuration> | |
489 | <property>multi.module.root</property> | |
490 | <project> | |
491 | <groupId>net.postgis</groupId> | |
492 | <artifactId>postgis-java-aggregator</artifactId> | |
493 | </project> | |
494 | </configuration> | |
495 | </execution> | |
496 | </executions> | |
497 | </plugin> | |
498 | 844 | <plugin> |
499 | 845 | <groupId>org.codehaus.mojo</groupId> |
500 | 846 | <artifactId>versions-maven-plugin</artifactId> |
519 | 865 | </build> |
520 | 866 | </profile> |
521 | 867 | <!-- |
522 | The release-sign-artifacts profile only needs activated when cutting a release for maven central. | |
523 | It will generate additional artifacts for javadoc and source as well as GPG signatures for each artifact. | |
524 | This profile also assumes that the properties for the gpg plugin (such as gpg.keyname and gpg.passphrase | |
525 | are either defined in a settings.xml file or similar facility. | |
868 | The release-sign-artifacts and sonatype deployment profiles only need activated when pushing snapshots or | |
869 | releases to maven central. When enabled, additional artifacts will be generated for javadoc and source as well | |
870 | as GPG signatures for each artifact. This profiles assume that the properties for the gpg plugin | |
871 | (such as gpg.keyname and gpg.passphrase are either defined in a settings.xml file or similar facility. | |
526 | 872 | --> |
527 | 873 | <profile> |
528 | 874 | <id>release-sign-artifacts</id> |
568 | 914 | </plugins> |
569 | 915 | </build> |
570 | 916 | </profile> |
917 | <profile> | |
918 | <id>sonatype-deployment</id> | |
919 | <distributionManagement> | |
920 | <snapshotRepository> | |
921 | <id>ossrh</id> | |
922 | <url>https://oss.sonatype.org/content/repositories/snapshots</url> | |
923 | </snapshotRepository> | |
924 | <repository> | |
925 | <id>ossrh</id> | |
926 | <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> | |
927 | </repository> | |
928 | </distributionManagement> | |
929 | </profile> | |
571 | 930 | |
572 | 931 | <profile> |
573 | 932 | <id>SkipUnitTests</id> |
584 | 943 | </profile> |
585 | 944 | </profiles> |
586 | 945 | |
587 | </project>⏎ | |
946 | </project> |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
2 | <modelVersion>4.0.0</modelVersion> | |
3 | ||
4 | <parent> | |
5 | <groupId>net.postgis</groupId> | |
6 | <artifactId>postgis-java-aggregator</artifactId> | |
7 | <version>2.5.0</version> | |
8 | </parent> | |
9 | ||
10 | <artifactId>postgis-geometry</artifactId> | |
11 | <version>2.5.0</version> | |
12 | <packaging>jar</packaging> | |
13 | ||
14 | <name>PostGIS Geometry</name> | |
15 | <description>Geometry classes provided by PostGIS JDBC Extension</description> | |
16 | ||
17 | <properties /> | |
18 | ||
19 | <dependencies> | |
20 | <dependency> | |
21 | <groupId>net.postgis.tools</groupId> | |
22 | <artifactId>test-utils</artifactId> | |
23 | <version>2.5.0</version> | |
24 | <scope>test</scope> | |
25 | </dependency> | |
26 | </dependencies> | |
27 | ||
28 | <build> | |
29 | <resources> | |
30 | <resource> | |
31 | <directory>src/main/resources</directory> | |
32 | <filtering>true</filtering> | |
33 | </resource> | |
34 | </resources> | |
35 | <testResources> | |
36 | <testResource> | |
37 | <directory>src/test/resources</directory> | |
38 | </testResource> | |
39 | <testResource> | |
40 | <directory>src/test/resources-filtered</directory> | |
41 | <filtering>true</filtering> | |
42 | </testResource> | |
43 | </testResources> | |
44 | <plugins> | |
45 | <plugin> | |
46 | <groupId>org.apache.maven.plugins</groupId> | |
47 | <artifactId>maven-surefire-plugin</artifactId> | |
48 | <configuration> | |
49 | <skip>${maven.test.skip}</skip> | |
50 | <forkCount>${surefire.forkCount}</forkCount> | |
51 | <useSystemClassLoader>${surefire.useSystemClassLoader}</useSystemClassLoader> | |
52 | <suiteXmlFiles> | |
53 | <suiteXmlFile>${project.build.testOutputDirectory}/testng.xml</suiteXmlFile> | |
54 | </suiteXmlFiles> | |
55 | </configuration> | |
56 | </plugin> | |
57 | </plugins> | |
58 | </build> | |
59 | ||
60 | </project> |
0 | /* | |
1 | * ComposedGeom.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | import java.util.Iterator; | |
31 | import java.util.List; | |
32 | ||
33 | /** | |
34 | * ComposedGeom - Abstract base class for all Geometries that are composed out | |
35 | * of other Geometries. | |
36 | * | |
37 | * In fact, this currently are all Geometry subclasses except Point. | |
38 | * | |
39 | * @author markus.schaber@logix-tt.com | |
40 | * | |
41 | * | |
42 | */ | |
43 | public abstract class ComposedGeom extends Geometry { | |
44 | /* JDK 1.5 Serialization */ | |
45 | private static final long serialVersionUID = 0x100; | |
46 | ||
47 | public static final Geometry[] EMPTY = new Geometry[0]; | |
48 | ||
49 | /** | |
50 | * The Array containing the geometries | |
51 | * | |
52 | * This is only to be exposed by concrete subclasses, to retain type safety. | |
53 | */ | |
54 | protected Geometry[] subgeoms = EMPTY; | |
55 | ||
56 | /** | |
57 | * Constructs an instance with the specified type | |
58 | * | |
59 | * @param type int value corresponding to the geometry type. | |
60 | */ | |
61 | public ComposedGeom(int type) { | |
62 | super(type); | |
63 | } | |
64 | ||
65 | public Geometry getSubGeometry(int index) { | |
66 | return subgeoms[index]; | |
67 | } | |
68 | ||
69 | public int numGeoms() { | |
70 | return subgeoms.length; | |
71 | } | |
72 | ||
73 | protected ComposedGeom(int type, Geometry[] geoms) { | |
74 | this(type); | |
75 | this.subgeoms = geoms; | |
76 | if (geoms.length > 0) { | |
77 | dimension = geoms[0].dimension; | |
78 | haveMeasure = geoms[0].haveMeasure; | |
79 | } else { | |
80 | dimension = 0; | |
81 | } | |
82 | } | |
83 | ||
84 | protected ComposedGeom(int type, String value, boolean haveM) throws SQLException { | |
85 | super(type); | |
86 | value = initSRID(value); | |
87 | ||
88 | String typestring = getTypeString(); | |
89 | if (value.indexOf(typestring) == 0) { | |
90 | int pfxlen = typestring.length(); | |
91 | if (value.charAt(pfxlen) == 'M') { | |
92 | pfxlen += 1; | |
93 | haveM = true; | |
94 | } | |
95 | value = value.substring(pfxlen).trim(); | |
96 | } else if (value.charAt(0) != '(') { | |
97 | // we are neigher inner nor outer rep. | |
98 | throw new SQLException("Error parsing a " + typestring + " out of " + value); | |
99 | } | |
100 | if (value.equals("(EMPTY)")) { | |
101 | // Special case for PostGIS 0.X style empty geometry collections | |
102 | // (which are not OpenGIS compliant) | |
103 | return; | |
104 | } | |
105 | ||
106 | String valueNoParans = GeometryTokenizer.removeLeadingAndTrailingStrings(value, "(", ")"); | |
107 | List<String> tokens = GeometryTokenizer.tokenize(valueNoParans, ','); | |
108 | ||
109 | int subgeomcount = tokens.size(); | |
110 | subgeoms = createSubGeomArray(subgeomcount); | |
111 | for (int p = 0; p < subgeomcount; p++) { | |
112 | subgeoms[p] = createSubGeomInstance(tokens.get(p), haveM); | |
113 | } | |
114 | dimension = subgeoms[0].dimension; | |
115 | // fetch haveMeasure from sub-point because haveM does only work with | |
116 | // 2d+M, not with 3d+M geometries | |
117 | haveMeasure = subgeoms[0].haveMeasure; | |
118 | } | |
119 | ||
120 | /** | |
121 | * Return the appropriate instance of the sub-geometry - this encapsulates | |
122 | * subclass specific constructor calls | |
123 | * | |
124 | * @param token The token containing the value for the sub-geometry | |
125 | * @param haveM flag to indicate the existence of a measure | |
126 | * @return the new sub-geometry | |
127 | * @throws SQLException if a SQLException is thrown | |
128 | */ | |
129 | protected abstract Geometry createSubGeomInstance(String token, boolean haveM) throws SQLException; | |
130 | ||
131 | /** | |
132 | * Return the appropriate instance of the sub-geometry array - this | |
133 | * encapsulates subclass specific array instantiation | |
134 | * | |
135 | * @param size number of elements in the array | |
136 | * @return Geometry array corresponding to the sub-geometry | |
137 | */ | |
138 | protected abstract Geometry[] createSubGeomArray(int size); | |
139 | ||
140 | protected boolean equalsintern(Geometry other) { | |
141 | // Can be assumed to be the same subclass of Geometry, so it must be a | |
142 | // ComposedGeom, too. | |
143 | ComposedGeom cother = (ComposedGeom) other; | |
144 | ||
145 | if (cother.subgeoms == null && subgeoms == null) { | |
146 | return true; | |
147 | } else if (cother.subgeoms == null || subgeoms == null) { | |
148 | return false; | |
149 | } else if (cother.subgeoms.length != subgeoms.length) { | |
150 | return false; | |
151 | } else if (subgeoms.length == 0) { | |
152 | return true; | |
153 | } else { | |
154 | for (int i = 0; i < subgeoms.length; i++) { | |
155 | if (!cother.subgeoms[i].equalsintern(this.subgeoms[i])) { | |
156 | return false; | |
157 | } | |
158 | } | |
159 | } | |
160 | return true; | |
161 | } | |
162 | ||
163 | public int numPoints() { | |
164 | if ((subgeoms == null) || (subgeoms.length == 0)) { | |
165 | return 0; | |
166 | } else { | |
167 | int result = 0; | |
168 | for (int i = 0; i < subgeoms.length; i++) { | |
169 | result += subgeoms[i].numPoints(); | |
170 | } | |
171 | return result; | |
172 | } | |
173 | } | |
174 | ||
175 | public Point getPoint(int n) { | |
176 | if (n < 0) { | |
177 | throw new ArrayIndexOutOfBoundsException("Negative index not allowed"); | |
178 | } else if ((subgeoms == null) || (subgeoms.length == 0)) { | |
179 | throw new ArrayIndexOutOfBoundsException("Empty Geometry has no Points!"); | |
180 | } else { | |
181 | for (int i = 0; i < subgeoms.length; i++) { | |
182 | ||
183 | Geometry current = subgeoms[i]; | |
184 | int np = current.numPoints(); | |
185 | if (n < np) { | |
186 | return current.getPoint(n); | |
187 | } else { | |
188 | n -= np; | |
189 | } | |
190 | } | |
191 | throw new ArrayIndexOutOfBoundsException("Index too large!"); | |
192 | } | |
193 | } | |
194 | ||
195 | /** | |
196 | * Optimized version | |
197 | */ | |
198 | public Point getLastPoint() { | |
199 | if ((subgeoms == null) || (subgeoms.length == 0)) { | |
200 | throw new ArrayIndexOutOfBoundsException("Empty Geometry has no Points!"); | |
201 | } else { | |
202 | return subgeoms[subgeoms.length - 1].getLastPoint(); | |
203 | } | |
204 | } | |
205 | ||
206 | /** | |
207 | * Optimized version | |
208 | */ | |
209 | public Point getFirstPoint() { | |
210 | if ((subgeoms == null) || (subgeoms.length == 0)) { | |
211 | throw new ArrayIndexOutOfBoundsException("Empty Geometry has no Points!"); | |
212 | } else { | |
213 | return subgeoms[0].getFirstPoint(); | |
214 | } | |
215 | } | |
216 | ||
217 | public Iterator iterator() { | |
218 | return java.util.Arrays.asList(subgeoms).iterator(); | |
219 | } | |
220 | ||
221 | public boolean isEmpty() { | |
222 | return (subgeoms == null) || (subgeoms.length == 0); | |
223 | } | |
224 | ||
225 | protected void mediumWKT(StringBuffer sb) { | |
226 | if ((subgeoms == null) || (subgeoms.length == 0)) { | |
227 | sb.append(" EMPTY"); | |
228 | } else { | |
229 | sb.append('('); | |
230 | innerWKT(sb); | |
231 | sb.append(')'); | |
232 | } | |
233 | } | |
234 | ||
235 | protected void innerWKT(StringBuffer sb) { | |
236 | subgeoms[0].mediumWKT(sb); | |
237 | for (int i = 1; i < subgeoms.length; i++) { | |
238 | sb.append(','); | |
239 | subgeoms[i].mediumWKT(sb); | |
240 | } | |
241 | } | |
242 | ||
243 | // Hashing - still buggy! | |
244 | boolean nohash = true; | |
245 | int hashcode = 0; | |
246 | ||
247 | public int hashCode() { | |
248 | if (nohash) { | |
249 | hashcode = super.hashCode() ^ subgeoms.hashCode(); | |
250 | nohash = false; | |
251 | } | |
252 | return hashcode; | |
253 | } | |
254 | ||
255 | public boolean checkConsistency() { | |
256 | if (super.checkConsistency()) { | |
257 | if (isEmpty()) { | |
258 | return true; | |
259 | } | |
260 | // cache to avoid getMember opcode | |
261 | int _dimension = this.dimension; | |
262 | boolean _haveMeasure = this.haveMeasure; | |
263 | int _srid = this.srid; | |
264 | for (int i = 0; i < subgeoms.length; i++) { | |
265 | Geometry sub = subgeoms[i]; | |
266 | if (!(sub.checkConsistency() && sub.dimension == _dimension | |
267 | && sub.haveMeasure == _haveMeasure && sub.srid == _srid)) { | |
268 | return false; | |
269 | } | |
270 | } | |
271 | return true; | |
272 | } else { | |
273 | return false; | |
274 | } | |
275 | } | |
276 | ||
277 | public void setSrid(int srid) { | |
278 | super.setSrid(srid); | |
279 | for (int i = 0; i < subgeoms.length; i++) { | |
280 | subgeoms[i].setSrid(srid); | |
281 | } | |
282 | } | |
283 | } |
0 | /* | |
1 | * Geometry.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | import java.io.Serializable; | |
30 | ||
31 | /** The base class of all geometries */ | |
32 | public abstract class Geometry implements Serializable { | |
33 | /* JDK 1.5 Serialization */ | |
34 | private static final long serialVersionUID = 0x100; | |
35 | ||
36 | // OpenGIS Geometry types as defined in the OGC WKB Spec | |
37 | // (May we replace this with an ENUM as soon as JDK 1.5 | |
38 | // has gained widespread usage?) | |
39 | ||
40 | /** Fake type for linear ring */ | |
41 | public static final int LINEARRING = 0; | |
42 | /** | |
43 | * The OGIS geometry type number for points. | |
44 | */ | |
45 | public static final int POINT = 1; | |
46 | ||
47 | /** | |
48 | * The OGIS geometry type number for lines. | |
49 | */ | |
50 | public static final int LINESTRING = 2; | |
51 | ||
52 | /** | |
53 | * The OGIS geometry type number for polygons. | |
54 | */ | |
55 | public static final int POLYGON = 3; | |
56 | ||
57 | /** | |
58 | * The OGIS geometry type number for aggregate points. | |
59 | */ | |
60 | public static final int MULTIPOINT = 4; | |
61 | ||
62 | /** | |
63 | * The OGIS geometry type number for aggregate lines. | |
64 | */ | |
65 | public static final int MULTILINESTRING = 5; | |
66 | ||
67 | /** | |
68 | * The OGIS geometry type number for aggregate polygons. | |
69 | */ | |
70 | public static final int MULTIPOLYGON = 6; | |
71 | ||
72 | /** | |
73 | * The OGIS geometry type number for feature collections. | |
74 | */ | |
75 | public static final int GEOMETRYCOLLECTION = 7; | |
76 | ||
77 | public static final String[] ALLTYPES = new String[] { | |
78 | "", // internally used LinearRing does not have any text in front of | |
79 | // it | |
80 | "POINT", "LINESTRING", "POLYGON", "MULTIPOINT", "MULTILINESTRING", | |
81 | "MULTIPOLYGON", "GEOMETRYCOLLECTION" }; | |
82 | ||
83 | /** | |
84 | * The Text representations of the geometry types | |
85 | * | |
86 | * @param type int value of the type to lookup | |
87 | * @return String reprentation of the type. | |
88 | */ | |
89 | public static String getTypeString(int type) { | |
90 | if (type >= 0 && type <= 7) { | |
91 | return ALLTYPES[type]; | |
92 | } else { | |
93 | throw new IllegalArgumentException("Unknown Geometry type" + type); | |
94 | } | |
95 | } | |
96 | ||
97 | // Properties common to all geometries | |
98 | /** | |
99 | * The dimensionality of this feature (2,3) | |
100 | */ | |
101 | public int dimension; | |
102 | ||
103 | /** | |
104 | * Do we have a measure (4th dimension) | |
105 | */ | |
106 | public boolean haveMeasure = false; | |
107 | ||
108 | /** | |
109 | * The OGIS geometry type of this feature. this is final as it never | |
110 | * changes, it is bound to the subclass of the instance. | |
111 | */ | |
112 | public final int type; | |
113 | ||
114 | /** | |
115 | * Official UNKNOWN srid value | |
116 | */ | |
117 | public final static int UNKNOWN_SRID = 0; | |
118 | ||
119 | /** | |
120 | * The spacial reference system id of this geometry, default is no srid | |
121 | */ | |
122 | public int srid = UNKNOWN_SRID; | |
123 | ||
124 | /** | |
125 | * Parse a SRID value, anything {@code <= 0} is unknown | |
126 | * | |
127 | * @param srid the SRID to parse | |
128 | * @return parsed SRID value | |
129 | */ | |
130 | public static int parseSRID(int srid) { | |
131 | if (srid < 0) { | |
132 | /* TODO: raise a warning ? */ | |
133 | srid = 0; | |
134 | } | |
135 | return srid; | |
136 | } | |
137 | ||
138 | /** | |
139 | * Constructor for subclasses | |
140 | * | |
141 | * @param type | |
142 | * has to be given by all subclasses. | |
143 | */ | |
144 | protected Geometry(int type) { | |
145 | this.type = type; | |
146 | } | |
147 | ||
148 | /** | |
149 | * java.lang.Object hashCode implementation | |
150 | */ | |
151 | public int hashCode() { | |
152 | return dimension | (type * 4) | (srid * 32); | |
153 | } | |
154 | ||
155 | /** | |
156 | * java.lang.Object equals implementation | |
157 | * | |
158 | * @param other geometry to compare | |
159 | * @return true if equal, false otherwise | |
160 | */ | |
161 | public boolean equals(Object other) { | |
162 | return (other != null) && (other instanceof Geometry) | |
163 | && equals((Geometry) other); | |
164 | } | |
165 | ||
166 | /** | |
167 | * geometry specific equals implementation - only defined for non-null | |
168 | * values | |
169 | * | |
170 | * @param other geometry to compare | |
171 | * @return true if equal, false otherwise | |
172 | */ | |
173 | public boolean equals(Geometry other) { | |
174 | return (other != null) && (this.dimension == other.dimension) | |
175 | && (this.type == other.type) && (this.srid == other.srid) | |
176 | && (this.haveMeasure == other.haveMeasure) | |
177 | && other.getClass().equals(this.getClass()) | |
178 | && this.equalsintern(other); | |
179 | } | |
180 | ||
181 | /** | |
182 | * Whether test coordinates for geometry - subclass specific code | |
183 | * | |
184 | * Implementors can assume that dimensin, type, srid and haveMeasure are | |
185 | * equal, other != null and other is the same subclass. | |
186 | * | |
187 | * @param other geometry to compare | |
188 | * @return true if equal, false otherwise | |
189 | */ | |
190 | protected abstract boolean equalsintern(Geometry other); | |
191 | ||
192 | /** | |
193 | * Return the number of Points of the geometry | |
194 | * | |
195 | * @return number of points in the geometry | |
196 | */ | |
197 | public abstract int numPoints(); | |
198 | ||
199 | /** | |
200 | * Get the nth Point of the geometry | |
201 | * | |
202 | * @param n the index of the point, from 0 to numPoints()-1; | |
203 | * @return nth point in the geometry | |
204 | * @throws ArrayIndexOutOfBoundsException in case of an emtpy geometry or bad index. | |
205 | */ | |
206 | public abstract Point getPoint(int n); | |
207 | ||
208 | /** | |
209 | * Same as getPoint(0); | |
210 | * | |
211 | * @return the initial Point in this geometry | |
212 | */ | |
213 | public abstract Point getFirstPoint(); | |
214 | ||
215 | /** | |
216 | * Same as getPoint(numPoints()-1); | |
217 | * | |
218 | * @return the final Point in this geometry | |
219 | */ | |
220 | public abstract Point getLastPoint(); | |
221 | ||
222 | /** | |
223 | * The OGIS geometry type number of this geometry. | |
224 | * | |
225 | * @return int value representation for the type of this geometry | |
226 | */ | |
227 | public int getType() { | |
228 | return this.type; | |
229 | } | |
230 | ||
231 | /** | |
232 | * Return the Type as String | |
233 | * | |
234 | * @return String representation for the type of this geometry | |
235 | */ | |
236 | public String getTypeString() { | |
237 | return getTypeString(this.type); | |
238 | } | |
239 | ||
240 | /** | |
241 | * Returns whether we have a measure | |
242 | * | |
243 | * @return true if the geometry has a measure, false otherwise | |
244 | */ | |
245 | public boolean isMeasured() { | |
246 | return haveMeasure; | |
247 | } | |
248 | ||
249 | /** | |
250 | * Queries the number of geometric dimensions of this geometry. This does | |
251 | * not include measures, as opposed to the server. | |
252 | * | |
253 | * @return The dimensionality (eg, 2D or 3D) of this geometry. | |
254 | */ | |
255 | public int getDimension() { | |
256 | return this.dimension; | |
257 | } | |
258 | ||
259 | /** | |
260 | * The OGIS geometry type number of this geometry. | |
261 | * | |
262 | * @return the SRID of this geometry | |
263 | */ | |
264 | public int getSrid() { | |
265 | return this.srid; | |
266 | } | |
267 | ||
268 | /** | |
269 | * Recursively sets the srid on this geometry and all contained | |
270 | * subgeometries | |
271 | * | |
272 | * @param srid the SRID for this geometry | |
273 | */ | |
274 | public void setSrid(int srid) { | |
275 | this.srid = srid; | |
276 | } | |
277 | ||
278 | public String toString() { | |
279 | StringBuffer sb = new StringBuffer(); | |
280 | if (srid != UNKNOWN_SRID) { | |
281 | sb.append("SRID="); | |
282 | sb.append(srid); | |
283 | sb.append(';'); | |
284 | } | |
285 | outerWKT(sb, true); | |
286 | return sb.toString(); | |
287 | } | |
288 | ||
289 | /** | |
290 | * Render the WKT version of this Geometry (without SRID) into the given | |
291 | * StringBuffer. | |
292 | * | |
293 | * @param sb StringBuffer to render into | |
294 | * @param putM flag to indicate if the M character should be used. | |
295 | */ | |
296 | public void outerWKT(StringBuffer sb, boolean putM) { | |
297 | sb.append(getTypeString()); | |
298 | if (putM && haveMeasure && dimension == 2) { | |
299 | sb.append('M'); | |
300 | } | |
301 | mediumWKT(sb); | |
302 | } | |
303 | ||
304 | public final void outerWKT(StringBuffer sb) { | |
305 | outerWKT(sb, true); | |
306 | } | |
307 | ||
308 | /** | |
309 | * Render the WKT without the type name, but including the brackets into the | |
310 | * StringBuffer | |
311 | * | |
312 | * @param sb StringBuffer to render into | |
313 | */ | |
314 | protected void mediumWKT(StringBuffer sb) { | |
315 | sb.append('('); | |
316 | innerWKT(sb); | |
317 | sb.append(')'); | |
318 | } | |
319 | ||
320 | /** | |
321 | * Render the "inner" part of the WKT (inside the brackets) into the | |
322 | * StringBuffer. | |
323 | * | |
324 | * @param SB StringBuffer to render into | |
325 | */ | |
326 | protected abstract void innerWKT(StringBuffer SB); | |
327 | ||
328 | /** | |
329 | * backwards compatibility method | |
330 | * | |
331 | * @return String representation of the value for the geometry. | |
332 | */ | |
333 | public String getValue() { | |
334 | StringBuffer sb = new StringBuffer(); | |
335 | mediumWKT(sb); | |
336 | return sb.toString(); | |
337 | } | |
338 | ||
339 | /** | |
340 | * Do some internal consistency checks on the geometry. | |
341 | * | |
342 | * Currently, all Geometries must have a valid dimension (2 or 3) and a | |
343 | * valid type. 2-dimensional Points must have Z=0.0, as well as non-measured | |
344 | * Points must have m=0.0. Composed geometries must have all equal SRID, | |
345 | * dimensionality and measures, as well as that they do not contain NULL or | |
346 | * inconsistent subgeometries. | |
347 | * | |
348 | * BinaryParser and WKTParser should only generate consistent geometries. | |
349 | * BinaryWriter may produce invalid results on inconsistent geometries. | |
350 | * | |
351 | * @return true if all checks are passed. | |
352 | */ | |
353 | public boolean checkConsistency() { | |
354 | return (dimension >= 2 && dimension <= 3) && (type >= 0 && type <= 7); | |
355 | } | |
356 | ||
357 | /** | |
358 | * Splits the SRID=4711; part of a EWKT rep if present and sets the srid. | |
359 | * | |
360 | * @param value String value to extract the SRID from | |
361 | * @return value without the SRID=4711; part | |
362 | */ | |
363 | protected String initSRID(String value) { | |
364 | value = value.trim(); | |
365 | if (value.startsWith("SRID=")) { | |
366 | int index = value.indexOf(';', 5); // sridprefix length is 5 | |
367 | if (index == -1) { | |
368 | throw new IllegalArgumentException( | |
369 | "Error parsing Geometry - SRID not delimited with ';' "); | |
370 | } else { | |
371 | this.srid = Integer.parseInt(value.substring(5, index)); | |
372 | return value.substring(index + 1).trim(); | |
373 | } | |
374 | } else { | |
375 | return value; | |
376 | } | |
377 | } | |
378 | } |
0 | package org.postgis; | |
1 | ||
2 | ||
3 | import org.postgis.binary.BinaryParser; | |
4 | ||
5 | import java.sql.SQLException; | |
6 | ||
7 | ||
8 | /** | |
9 | * Builds geometry instances. | |
10 | * | |
11 | * Note: This class contains the word "builder" but does NOT implement the builder pattern (yet). | |
12 | * | |
13 | * @author Phillip Ross | |
14 | */ | |
15 | public class GeometryBuilder { | |
16 | ||
17 | /** The prefix that indicates SRID presence */ | |
18 | public static final String SRIDPREFIX = "SRID="; | |
19 | ||
20 | ||
21 | public static Geometry geomFromString(String value) throws SQLException { | |
22 | return geomFromString(value, false); | |
23 | } | |
24 | ||
25 | public static Geometry geomFromString(String value, boolean haveM) throws SQLException { | |
26 | BinaryParser bp = new BinaryParser(); | |
27 | ||
28 | return geomFromString(value, bp, haveM); | |
29 | } | |
30 | ||
31 | /** | |
32 | * Maybe we could add more error checking here? | |
33 | * | |
34 | * @param value String representing the geometry | |
35 | * @param bp BinaryParser to use whe parsing | |
36 | * @return Geometry object parsed from the specified string value | |
37 | * @throws SQLException when a SQLException occurs | |
38 | */ | |
39 | public static Geometry geomFromString(String value, BinaryParser bp) throws SQLException { | |
40 | return geomFromString(value, bp, false); | |
41 | } | |
42 | ||
43 | public static Geometry geomFromString(String value, BinaryParser bp, boolean haveM) | |
44 | throws SQLException { | |
45 | value = value.trim(); | |
46 | ||
47 | int srid = Geometry.UNKNOWN_SRID; | |
48 | ||
49 | if (value.startsWith(SRIDPREFIX)) { | |
50 | // break up geometry into srid and wkt | |
51 | String[] parts = splitSRID(value); | |
52 | value = parts[1].trim(); | |
53 | srid = Geometry.parseSRID(Integer.parseInt(parts[0].substring(5))); | |
54 | } | |
55 | ||
56 | Geometry result; | |
57 | if (value.startsWith("00") || value.startsWith("01")) { | |
58 | result = bp.parse(value); | |
59 | } else if (value.endsWith("EMPTY")) { | |
60 | // We have a standard conforming representation for an empty | |
61 | // geometry which is to be parsed as an empty GeometryCollection. | |
62 | result = new GeometryCollection(); | |
63 | } else if (value.startsWith("MULTIPOLYGON")) { | |
64 | result = new MultiPolygon(value, haveM); | |
65 | } else if (value.startsWith("MULTILINESTRING")) { | |
66 | result = new MultiLineString(value, haveM); | |
67 | } else if (value.startsWith("MULTIPOINT")) { | |
68 | result = new MultiPoint(value, haveM); | |
69 | } else if (value.startsWith("POLYGON")) { | |
70 | result = new Polygon(value, haveM); | |
71 | } else if (value.startsWith("LINESTRING")) { | |
72 | result = new LineString(value, haveM); | |
73 | } else if (value.startsWith("POINT")) { | |
74 | result = new Point(value, haveM); | |
75 | } else if (value.startsWith("GEOMETRYCOLLECTION")) { | |
76 | result = new GeometryCollection(value, haveM); | |
77 | } else { | |
78 | throw new SQLException("Unknown type: " + value); | |
79 | } | |
80 | ||
81 | if (srid != Geometry.UNKNOWN_SRID) { | |
82 | result.srid = srid; | |
83 | } | |
84 | ||
85 | return result; | |
86 | } | |
87 | ||
88 | ||
89 | /** | |
90 | * Splits a String at the first occurrence of border character. | |
91 | * | |
92 | * Poor man's String.split() replacement, as String.split() was invented at | |
93 | * jdk1.4, and the Debian PostGIS Maintainer had problems building the woody | |
94 | * backport of his package using DFSG-free compilers. In all the cases we | |
95 | * used split() in the org.postgis package, we only needed to split at the | |
96 | * first occurence, and thus this code could even be faster. | |
97 | * | |
98 | * @param whole the String to be split | |
99 | * @return String array containing the split elements | |
100 | * @throws SQLException when a SQLException occurrs | |
101 | */ | |
102 | public static String[] splitSRID(String whole) throws SQLException { | |
103 | int index = whole.indexOf(';', 5); // sridprefix length is 5 | |
104 | if (index == -1) { | |
105 | throw new SQLException("Error parsing Geometry - SRID not delimited with ';' "); | |
106 | } else { | |
107 | return new String[]{ | |
108 | whole.substring(0, index), | |
109 | whole.substring(index + 1)}; | |
110 | } | |
111 | } | |
112 | ||
113 | ||
114 | } |
0 | /* | |
1 | * GeometryCollection.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | ||
32 | /** | |
33 | * Geometry Collection class WARNING: Currently only implements empty | |
34 | * collections | |
35 | * | |
36 | * @author markus.schaber@logix-tt.com | |
37 | * | |
38 | */ | |
39 | ||
40 | public class GeometryCollection extends ComposedGeom { | |
41 | /* JDK 1.5 Serialization */ | |
42 | private static final long serialVersionUID = 0x100; | |
43 | ||
44 | public static final String GeoCollID = "GEOMETRYCOLLECTION"; | |
45 | ||
46 | public GeometryCollection() { | |
47 | super(GEOMETRYCOLLECTION); | |
48 | } | |
49 | ||
50 | public GeometryCollection(Geometry[] geoms) { | |
51 | super(GEOMETRYCOLLECTION, geoms); | |
52 | } | |
53 | ||
54 | public GeometryCollection(String value) throws SQLException { | |
55 | this(value, false); | |
56 | } | |
57 | ||
58 | public GeometryCollection(String value, boolean haveM) throws SQLException { | |
59 | super(GEOMETRYCOLLECTION, value, haveM); | |
60 | } | |
61 | ||
62 | protected Geometry[] createSubGeomArray(int ngeoms) { | |
63 | return new Geometry[ngeoms]; | |
64 | } | |
65 | ||
66 | protected Geometry createSubGeomInstance(String token, boolean haveM) throws SQLException { | |
67 | return GeometryBuilder.geomFromString(token, haveM); | |
68 | } | |
69 | ||
70 | protected void innerWKT(StringBuffer SB) { | |
71 | subgeoms[0].outerWKT(SB, true); | |
72 | for (int i = 1; i < subgeoms.length; i++) { | |
73 | SB.append(','); | |
74 | subgeoms[i].outerWKT(SB, true); | |
75 | } | |
76 | } | |
77 | ||
78 | public Geometry[] getGeometries() { | |
79 | return subgeoms; | |
80 | } | |
81 | } |
0 | /* | |
1 | * GeometryTokenizer.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | * | |
21 | */ | |
22 | ||
23 | package org.postgis; | |
24 | ||
25 | ||
26 | import java.util.ArrayList; | |
27 | import java.util.List; | |
28 | import java.util.Stack; | |
29 | ||
30 | ||
31 | public class GeometryTokenizer { | |
32 | ||
33 | ||
34 | public static List<String> tokenize(String string, char delimiter) { | |
35 | List<String> tokens = new ArrayList<>(); | |
36 | Stack<Character> stack = new Stack<>(); | |
37 | int consumed = 0; | |
38 | for (int position = 0; position < string.length(); position++) { | |
39 | char character = string.charAt(position); | |
40 | if ((character == '(') || (character == '[')) { | |
41 | stack.push(character); | |
42 | } else if (((character == ')') && (stack.peek() == '(')) || | |
43 | ((character == ']') && (stack.peek() == '[')) | |
44 | ) { | |
45 | stack.pop(); | |
46 | } | |
47 | if ((character == delimiter) && (stack.size() == 0)) { | |
48 | tokens.add(string.substring(consumed, position)); | |
49 | consumed = position + 1; | |
50 | } | |
51 | } | |
52 | if (consumed < string.length()) { | |
53 | tokens.add(string.substring(consumed)); | |
54 | } | |
55 | return tokens; | |
56 | } | |
57 | ||
58 | ||
59 | public static String removeLeadingAndTrailingStrings(String string, String leadingString, String trailingString) { | |
60 | int startIndex = string.indexOf(leadingString); | |
61 | if (startIndex == -1) { | |
62 | startIndex = 0; | |
63 | } else { | |
64 | startIndex += leadingString.length(); | |
65 | } | |
66 | ||
67 | int endIndex = string.lastIndexOf(trailingString); | |
68 | if (endIndex == -1) { | |
69 | endIndex = string.length(); | |
70 | } | |
71 | return string.substring(startIndex, endIndex); | |
72 | } | |
73 | ||
74 | ||
75 | }⏎ |
0 | /* | |
1 | * LineString.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | public class LineString extends PointComposedGeom { | |
32 | /* JDK 1.5 Serialization */ | |
33 | private static final long serialVersionUID = 0x100; | |
34 | ||
35 | double len = -1.; | |
36 | ||
37 | public LineString() { | |
38 | super(LINESTRING); | |
39 | } | |
40 | ||
41 | public LineString(Point[] points) { | |
42 | super(LINESTRING, points); | |
43 | } | |
44 | ||
45 | public LineString(String value) throws SQLException { | |
46 | super(LINESTRING, value); | |
47 | } | |
48 | ||
49 | public LineString(String value, boolean haveM) throws SQLException { | |
50 | super(LINESTRING, value, haveM); | |
51 | } | |
52 | ||
53 | public LineString reverse() { | |
54 | Point[] points = this.getPoints(); | |
55 | int l = points.length; | |
56 | int i, j; | |
57 | Point[] p = new Point[l]; | |
58 | for (i = 0, j = l - 1; i < l; i++, j--) { | |
59 | p[i] = points[j]; | |
60 | } | |
61 | return new LineString(p); | |
62 | } | |
63 | ||
64 | public LineString concat(LineString other) { | |
65 | Point[] points = this.getPoints(); | |
66 | Point[] opoints = other.getPoints(); | |
67 | ||
68 | boolean cutPoint = this.getLastPoint() == null | |
69 | || this.getLastPoint().equals(other.getFirstPoint()); | |
70 | int count = points.length + opoints.length - (cutPoint ? 1 : 0); | |
71 | Point[] p = new Point[count]; | |
72 | ||
73 | // Maybe we should use System.arrayCopy here? | |
74 | int i, j; | |
75 | for (i = 0; i < points.length; i++) { | |
76 | p[i] = points[i]; | |
77 | } | |
78 | if (!cutPoint) { | |
79 | p[i++] = other.getFirstPoint(); | |
80 | } | |
81 | for (j = 1; j < opoints.length; j++, i++) { | |
82 | p[i] = opoints[j]; | |
83 | } | |
84 | return new LineString(p); | |
85 | } | |
86 | ||
87 | public double length() { | |
88 | if (len < 0) { | |
89 | Point[] points = this.getPoints(); | |
90 | if ((points == null) || (points.length < 2)) { | |
91 | len = 0; | |
92 | } else { | |
93 | double sum = 0; | |
94 | for (int i = 1; i < points.length; i++) { | |
95 | sum += points[i - 1].distance(points[i]); | |
96 | } | |
97 | len = sum; | |
98 | } | |
99 | } | |
100 | return len; | |
101 | } | |
102 | } |
0 | /* | |
1 | * LinearRing.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | import java.util.List; | |
31 | ||
32 | ||
33 | /** | |
34 | * This represents the LinearRing GIS datatype. This type is used to construct | |
35 | * the polygon types, but is not stored or retrieved directly from the database. | |
36 | */ | |
37 | public class LinearRing extends PointComposedGeom { | |
38 | /* JDK 1.5 Serialization */ | |
39 | private static final long serialVersionUID = 0x100; | |
40 | ||
41 | public LinearRing(Point[] points) { | |
42 | super(LINEARRING, points); | |
43 | } | |
44 | ||
45 | /** | |
46 | * This is called to construct a LinearRing from the PostGIS string | |
47 | * representation of a ring. | |
48 | * | |
49 | * @param value Definition of this ring in the PostGIS string format. | |
50 | * @throws SQLException when a SQLException occurs | |
51 | */ | |
52 | public LinearRing(String value) throws SQLException { | |
53 | this(value, false); | |
54 | } | |
55 | ||
56 | /** | |
57 | * @param value The text representation of this LinearRing | |
58 | * @param haveM Hint whether we have a measure. This is given to us by other | |
59 | * "parent" Polygon, and is passed further to our parent. | |
60 | * @throws SQLException when a SQLException occurs | |
61 | */ | |
62 | ||
63 | protected LinearRing(String value, boolean haveM) throws SQLException { | |
64 | super(LINEARRING); | |
65 | String valueNoParans = GeometryTokenizer.removeLeadingAndTrailingStrings(value.trim(), "(", ")"); | |
66 | List<String> tokens = GeometryTokenizer.tokenize(valueNoParans, ','); | |
67 | int npoints = tokens.size(); | |
68 | Point[] points = new Point[npoints]; | |
69 | for (int p = 0; p < npoints; p++) { | |
70 | points[p] = new Point(tokens.get(p), haveM); | |
71 | } | |
72 | this.dimension = points[0].dimension; | |
73 | // fetch haveMeasure from subpoint because haveM does only work with | |
74 | // 2d+M, not with 3d+M geometries | |
75 | this.haveMeasure = points[0].haveMeasure; | |
76 | this.subgeoms = points; | |
77 | } | |
78 | ||
79 | }⏎ |
0 | /* | |
1 | * MultiLineString.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | public class MultiLineString extends ComposedGeom { | |
32 | /* JDK 1.5 Serialization */ | |
33 | private static final long serialVersionUID = 0x100; | |
34 | ||
35 | double len = -1; | |
36 | ||
37 | public int hashCode() { | |
38 | return super.hashCode() ^ (int) this.length(); | |
39 | } | |
40 | ||
41 | public MultiLineString() { | |
42 | super(MULTILINESTRING); | |
43 | } | |
44 | ||
45 | public MultiLineString(LineString[] lines) { | |
46 | super(MULTILINESTRING, lines); | |
47 | } | |
48 | ||
49 | public MultiLineString(String value) throws SQLException { | |
50 | this(value, false); | |
51 | } | |
52 | ||
53 | public MultiLineString(String value, boolean haveM) throws SQLException { | |
54 | super(MULTILINESTRING, value, haveM); | |
55 | } | |
56 | ||
57 | protected Geometry createSubGeomInstance(String token, boolean haveM) throws SQLException { | |
58 | return new LineString(token, haveM); | |
59 | } | |
60 | ||
61 | protected Geometry[] createSubGeomArray(int nlines) { | |
62 | return new LineString[nlines]; | |
63 | } | |
64 | ||
65 | public int numLines() { | |
66 | return subgeoms.length; | |
67 | } | |
68 | ||
69 | public LineString[] getLines() { | |
70 | return (LineString[]) subgeoms.clone(); | |
71 | } | |
72 | ||
73 | public LineString getLine(int idx) { | |
74 | if (idx >= 0 & idx < subgeoms.length) { | |
75 | return (LineString) subgeoms[idx]; | |
76 | } else { | |
77 | return null; | |
78 | } | |
79 | } | |
80 | ||
81 | public double length() { | |
82 | if (len < 0) { | |
83 | LineString[] lines = (LineString[]) subgeoms; | |
84 | if (lines.length < 1) { | |
85 | len = 0; | |
86 | } else { | |
87 | double sum = 0; | |
88 | for (int i = 0; i < lines.length; i++) { | |
89 | sum += lines[i].length(); | |
90 | } | |
91 | len = sum; | |
92 | } | |
93 | } | |
94 | return len; | |
95 | } | |
96 | } |
0 | /* | |
1 | * MultiPoint.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | public class MultiPoint extends PointComposedGeom { | |
32 | /* JDK 1.5 Serialization */ | |
33 | private static final long serialVersionUID = 0x100; | |
34 | ||
35 | public MultiPoint() { | |
36 | super(MULTIPOINT); | |
37 | } | |
38 | ||
39 | public MultiPoint(Point[] points) { | |
40 | super(MULTIPOINT, points); | |
41 | } | |
42 | ||
43 | public MultiPoint(String value) throws SQLException { | |
44 | this(value, false); | |
45 | } | |
46 | ||
47 | protected MultiPoint(String value, boolean haveM) throws SQLException { | |
48 | super(MULTIPOINT, value, haveM); | |
49 | } | |
50 | } |
0 | /* | |
1 | * MultiPolygon.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | public class MultiPolygon extends ComposedGeom { | |
32 | /* JDK 1.5 Serialization */ | |
33 | private static final long serialVersionUID = 0x100; | |
34 | ||
35 | public MultiPolygon() { | |
36 | super(MULTIPOLYGON); | |
37 | } | |
38 | ||
39 | public MultiPolygon(Polygon[] polygons) { | |
40 | super(MULTIPOLYGON, polygons); | |
41 | } | |
42 | ||
43 | public MultiPolygon(String value) throws SQLException { | |
44 | this(value, false); | |
45 | } | |
46 | ||
47 | protected MultiPolygon(String value, boolean haveM) throws SQLException { | |
48 | super(MULTIPOLYGON, value, haveM); | |
49 | } | |
50 | ||
51 | protected Geometry[] createSubGeomArray(int npolygons) { | |
52 | return new Polygon[npolygons]; | |
53 | } | |
54 | ||
55 | protected Geometry createSubGeomInstance(String token, boolean haveM) throws SQLException { | |
56 | return new Polygon(token, haveM); | |
57 | } | |
58 | ||
59 | public int numPolygons() { | |
60 | return subgeoms.length; | |
61 | } | |
62 | ||
63 | public Polygon getPolygon(int idx) { | |
64 | if (idx >= 0 & idx < subgeoms.length) { | |
65 | return (Polygon) subgeoms[idx]; | |
66 | } else { | |
67 | return null; | |
68 | } | |
69 | } | |
70 | ||
71 | public Polygon[] getPolygons() { | |
72 | return (Polygon[]) subgeoms; | |
73 | } | |
74 | } |
0 | /* | |
1 | * Point.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | import java.util.List; | |
31 | ||
32 | public class Point extends Geometry { | |
33 | /* JDK 1.5 Serialization */ | |
34 | private static final long serialVersionUID = 0x100; | |
35 | ||
36 | public static final boolean CUTINTS = true; | |
37 | ||
38 | public int hashCode() { | |
39 | return super.hashCode() ^ hashCode(x) ^ hashCode(y) ^ hashCode(z) ^ hashCode(m); | |
40 | } | |
41 | ||
42 | public static int hashCode(double value) { | |
43 | long v = Double.doubleToLongBits(value); | |
44 | return (int) (v ^ (v >>> 32)); | |
45 | } | |
46 | ||
47 | protected boolean equalsintern(Geometry otherg) { | |
48 | Point other = (Point) otherg; | |
49 | return equals(other); | |
50 | } | |
51 | ||
52 | public static boolean double_equals(double a, double b) { | |
53 | if ( Double.isNaN(a) && Double.isNaN(b) ) { | |
54 | return true; | |
55 | } | |
56 | else { | |
57 | return (a == b); | |
58 | } | |
59 | } | |
60 | ||
61 | public final boolean equals(Point other) { | |
62 | boolean xequals = double_equals(x, other.x); | |
63 | boolean yequals = double_equals(y, other.y); | |
64 | boolean zequals = ((dimension == 2) || double_equals(z, other.z)); | |
65 | boolean mequals = ((haveMeasure == false) || double_equals(m,other.m)); | |
66 | boolean result = xequals && yequals && zequals && mequals; | |
67 | return result; | |
68 | } | |
69 | ||
70 | public Point getPoint(int index) { | |
71 | if (index == 0) { | |
72 | return this; | |
73 | } else { | |
74 | throw new ArrayIndexOutOfBoundsException("Point only has a single Point! " + index); | |
75 | } | |
76 | } | |
77 | ||
78 | /** Optimized versions for this special case */ | |
79 | public Point getFirstPoint() { | |
80 | return this; | |
81 | } | |
82 | ||
83 | /** Optimized versions for this special case */ | |
84 | public Point getLastPoint() { | |
85 | return this; | |
86 | } | |
87 | ||
88 | public int numPoints() { | |
89 | return 1; | |
90 | } | |
91 | ||
92 | /** | |
93 | * The X coordinate of the point. | |
94 | * In most long/lat systems, this is the longitude. | |
95 | */ | |
96 | public double x; | |
97 | ||
98 | /** | |
99 | * The Y coordinate of the point. | |
100 | * In most long/lat systems, this is the latitude. | |
101 | */ | |
102 | public double y; | |
103 | ||
104 | /** | |
105 | * The Z coordinate of the point. | |
106 | * In most long/lat systems, this is a radius from the | |
107 | * center of the earth, or the height / elevation over | |
108 | * the ground. | |
109 | */ | |
110 | public double z; | |
111 | ||
112 | /** | |
113 | * The measure of the point. | |
114 | */ | |
115 | public double m = 0.0; | |
116 | ||
117 | public Point() { | |
118 | super(POINT); | |
119 | } | |
120 | ||
121 | /** Constructs a new Point | |
122 | * @param x the longitude / x ordinate | |
123 | * @param y the latitude / y ordinate | |
124 | * @param z the radius / height / elevation / z ordinate | |
125 | */ | |
126 | public Point(double x, double y, double z) { | |
127 | this(); | |
128 | this.x = x; | |
129 | this.y = y; | |
130 | this.z = z; | |
131 | dimension = 3; | |
132 | } | |
133 | ||
134 | /** Constructs a new Point | |
135 | * @param x the longitude / x ordinate | |
136 | * @param y the latitude / y ordinate | |
137 | */ | |
138 | public Point(double x, double y) { | |
139 | this(); | |
140 | this.x = x; | |
141 | this.y = y; | |
142 | this.z = 0.0; | |
143 | dimension = 2; | |
144 | } | |
145 | ||
146 | /** | |
147 | * Construct a Point from EWKT. | |
148 | * | |
149 | * (3D and measures are legal, but SRID is not allowed). | |
150 | * | |
151 | * @param value String representation of the geometry. | |
152 | * @throws SQLException when a SQLException occurs | |
153 | */ | |
154 | public Point(String value) throws SQLException { | |
155 | this(value, false); | |
156 | } | |
157 | ||
158 | /** | |
159 | * Construct a Point | |
160 | * | |
161 | * @param value The text representation of this point | |
162 | * @param haveM Hint whether we have a measure. This is used by other | |
163 | * geometries parsing inner points where we only get "1 2 3 4" | |
164 | * like strings without the "POINT(" and ")" stuff. If there | |
165 | * acutally is a POINTM prefix, this overrides the given value. | |
166 | * However, POINT does not set it to false, as they can be | |
167 | * contained in measured collections, as in | |
168 | * "GEOMETRYCOLLECTIONM(POINT(0 0 0))". | |
169 | * @throws SQLException when a SQLException occurs | |
170 | */ | |
171 | protected Point(String value, boolean haveM) throws SQLException { | |
172 | this(); | |
173 | value = initSRID(value); | |
174 | ||
175 | if (value.indexOf("POINTM") == 0) { | |
176 | haveM = true; | |
177 | value = value.substring(6).trim(); | |
178 | } else if (value.indexOf("POINT") == 0) { | |
179 | value = value.substring(5).trim(); | |
180 | } | |
181 | String valueNoParans = GeometryTokenizer.removeLeadingAndTrailingStrings(value, "(", ")"); | |
182 | List<String> tokens = GeometryTokenizer.tokenize(valueNoParans, ' '); | |
183 | try { | |
184 | x = Double.valueOf(tokens.get(0)).doubleValue(); | |
185 | y = Double.valueOf(tokens.get(1)).doubleValue(); | |
186 | haveM |= tokens.size() == 4; | |
187 | if ((tokens.size() == 3 && !haveM) || (tokens.size() == 4)) { | |
188 | z = Double.valueOf(tokens.get(2)).doubleValue(); | |
189 | dimension = 3; | |
190 | } else { | |
191 | dimension = 2; | |
192 | } | |
193 | if (haveM) { | |
194 | m = Double.valueOf(tokens.get(dimension)).doubleValue(); | |
195 | } | |
196 | } catch (NumberFormatException e) { | |
197 | throw new SQLException("Error parsing Point: " + e.toString()); | |
198 | } | |
199 | haveMeasure = haveM; | |
200 | } | |
201 | ||
202 | public void innerWKT(StringBuffer sb) { | |
203 | sb.append(x); | |
204 | if (CUTINTS) | |
205 | cutint(sb); | |
206 | sb.append(' '); | |
207 | sb.append(y); | |
208 | if (CUTINTS) | |
209 | cutint(sb); | |
210 | if (dimension == 3) { | |
211 | sb.append(' '); | |
212 | sb.append(z); | |
213 | if (CUTINTS) | |
214 | cutint(sb); | |
215 | } | |
216 | if (haveMeasure) { | |
217 | sb.append(' '); | |
218 | sb.append(m); | |
219 | if (CUTINTS) | |
220 | cutint(sb); | |
221 | } | |
222 | } | |
223 | ||
224 | private static void cutint(StringBuffer sb) { | |
225 | int l = sb.length() - 2; | |
226 | if ((sb.charAt(l + 1) == '0') && (sb.charAt(l) == '.')) { | |
227 | sb.setLength(l); | |
228 | } | |
229 | } | |
230 | ||
231 | public double getX() { | |
232 | return x; | |
233 | } | |
234 | ||
235 | public double getY() { | |
236 | return y; | |
237 | } | |
238 | ||
239 | public double getZ() { | |
240 | return z; | |
241 | } | |
242 | ||
243 | public double getM() { | |
244 | return m; | |
245 | } | |
246 | ||
247 | public void setX(double x) { | |
248 | this.x = x; | |
249 | } | |
250 | ||
251 | public void setY(double y) { | |
252 | this.y = y; | |
253 | } | |
254 | ||
255 | public void setZ(double z) { | |
256 | this.z = z; | |
257 | } | |
258 | ||
259 | public void setM(double m) { | |
260 | haveMeasure = true; | |
261 | this.m = m; | |
262 | } | |
263 | ||
264 | public void setX(int x) { | |
265 | this.x = x; | |
266 | } | |
267 | ||
268 | public void setY(int y) { | |
269 | this.y = y; | |
270 | } | |
271 | ||
272 | public void setZ(int z) { | |
273 | this.z = z; | |
274 | } | |
275 | ||
276 | public double distance(Point other) { | |
277 | double tx, ty, tz; | |
278 | if (this.dimension != other.dimension) { | |
279 | throw new IllegalArgumentException("Points have different dimensions!"); | |
280 | } | |
281 | tx = this.x - other.x; | |
282 | switch (this.dimension) { | |
283 | case 1 : | |
284 | return Math.sqrt(tx * tx); | |
285 | case 2 : | |
286 | ty = this.y - other.y; | |
287 | return Math.sqrt(tx * tx + ty * ty); | |
288 | case 3 : | |
289 | ty = this.y - other.y; | |
290 | tz = this.z - other.z; | |
291 | return Math.sqrt(tx * tx + ty * ty + tz * tz); | |
292 | default : | |
293 | throw new IllegalArgumentException("Illegal dimension of Point" + this.dimension); | |
294 | } | |
295 | } | |
296 | ||
297 | public boolean checkConsistency() { | |
298 | return super.checkConsistency() && (this.dimension == 3 || this.z == 0.0) | |
299 | && (this.haveMeasure || this.m == 0.0); | |
300 | } | |
301 | } |
0 | /* | |
1 | * PointComposedGeom.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | package org.postgis; | |
27 | ||
28 | import java.sql.SQLException; | |
29 | ||
30 | /** | |
31 | * PointComposedGeom - base class for all composed geoms that contain only | |
32 | * points. | |
33 | * | |
34 | * @author markus.schaber@logix-tt.com | |
35 | * | |
36 | */ | |
37 | ||
38 | public abstract class PointComposedGeom extends ComposedGeom { | |
39 | /* JDK 1.5 Serialization */ | |
40 | private static final long serialVersionUID = 0x100; | |
41 | ||
42 | protected PointComposedGeom(int type) { | |
43 | super(type); | |
44 | } | |
45 | ||
46 | protected PointComposedGeom(int type, Point[] points) { | |
47 | super(type, points); | |
48 | } | |
49 | ||
50 | public PointComposedGeom(int type, String value) throws SQLException { | |
51 | this(type, value, false); | |
52 | } | |
53 | ||
54 | public PointComposedGeom(int type, String value, boolean haveM) throws SQLException { | |
55 | super(type, value, haveM); | |
56 | } | |
57 | ||
58 | protected Geometry createSubGeomInstance(String token, boolean haveM) throws SQLException { | |
59 | return new Point(token, haveM); | |
60 | } | |
61 | ||
62 | protected Geometry[] createSubGeomArray(int pointcount) { | |
63 | return new Point[pointcount]; | |
64 | } | |
65 | ||
66 | protected void innerWKT(StringBuffer sb) { | |
67 | subgeoms[0].innerWKT(sb); | |
68 | for (int i = 1; i < subgeoms.length; i++) { | |
69 | sb.append(','); | |
70 | subgeoms[i].innerWKT(sb); | |
71 | } | |
72 | } | |
73 | ||
74 | /** | |
75 | * optimized version | |
76 | */ | |
77 | public int numPoints() { | |
78 | return subgeoms.length; | |
79 | } | |
80 | ||
81 | /** | |
82 | * optimized version | |
83 | */ | |
84 | public Point getPoint(int idx) { | |
85 | if (idx >= 0 & idx < subgeoms.length) { | |
86 | return (Point) subgeoms[idx]; | |
87 | } else { | |
88 | return null; | |
89 | } | |
90 | } | |
91 | ||
92 | /** | |
93 | * Get the underlying Point array | |
94 | * | |
95 | * @return an array of Points within this geometry | |
96 | */ | |
97 | public Point[] getPoints() { | |
98 | return (Point[]) subgeoms; | |
99 | } | |
100 | } |
0 | /* | |
1 | * Polygon.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | public class Polygon extends ComposedGeom { | |
32 | /* JDK 1.5 Serialization */ | |
33 | private static final long serialVersionUID = 0x100; | |
34 | ||
35 | public Polygon() { | |
36 | super(POLYGON); | |
37 | } | |
38 | ||
39 | public Polygon(LinearRing[] rings) { | |
40 | super(POLYGON, rings); | |
41 | } | |
42 | ||
43 | public Polygon(String value) throws SQLException { | |
44 | this(value, false); | |
45 | } | |
46 | ||
47 | public Polygon(String value, boolean haveM) throws SQLException { | |
48 | super(POLYGON, value, haveM); | |
49 | } | |
50 | ||
51 | protected Geometry createSubGeomInstance(String token, boolean haveM) throws SQLException { | |
52 | return new LinearRing(token, haveM); | |
53 | } | |
54 | ||
55 | protected Geometry[] createSubGeomArray(int ringcount) { | |
56 | return new LinearRing[ringcount]; | |
57 | } | |
58 | ||
59 | public int numRings() { | |
60 | return subgeoms.length; | |
61 | } | |
62 | ||
63 | public LinearRing getRing(int idx) { | |
64 | if (idx >= 0 & idx < subgeoms.length) { | |
65 | return (LinearRing) subgeoms[idx]; | |
66 | } else { | |
67 | return null; | |
68 | } | |
69 | } | |
70 | } |
0 | /* | |
1 | * BinaryParser.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Parser | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | package org.postgis.binary; | |
25 | ||
26 | import org.postgis.Geometry; | |
27 | import org.postgis.GeometryCollection; | |
28 | import org.postgis.LineString; | |
29 | import org.postgis.LinearRing; | |
30 | import org.postgis.MultiLineString; | |
31 | import org.postgis.MultiPoint; | |
32 | import org.postgis.MultiPolygon; | |
33 | import org.postgis.Point; | |
34 | import org.postgis.Polygon; | |
35 | import org.postgis.binary.ByteGetter.BinaryByteGetter; | |
36 | import org.postgis.binary.ByteGetter.StringByteGetter; | |
37 | ||
38 | ||
39 | /** | |
40 | * Parse binary representation of geometries. | |
41 | * | |
42 | * It should be easy to add char[] and CharSequence ByteGetter instances, | |
43 | * although the latter one is not compatible with older jdks. | |
44 | * | |
45 | * I did not implement real unsigned 32-bit integers or emulate them with long, | |
46 | * as both java Arrays and Strings currently can have only 2^31-1 elements | |
47 | * (bytes), so we cannot even get or build Geometries with more than approx. | |
48 | * 2^28 coordinates (8 bytes each). | |
49 | * | |
50 | * @author {@literal Markus Schaber <markus.schaber@logix-tt.com>} | |
51 | * | |
52 | */ | |
53 | public class BinaryParser { | |
54 | ||
55 | /** | |
56 | * Get the appropriate ValueGetter for my endianness | |
57 | * | |
58 | * @param bytes The appropriate Byte Getter | |
59 | * | |
60 | * @return the ValueGetter | |
61 | */ | |
62 | public static ValueGetter valueGetterForEndian(ByteGetter bytes) { | |
63 | if (bytes.get(0) == ValueGetter.XDR.NUMBER) { // XDR | |
64 | return new ValueGetter.XDR(bytes); | |
65 | } else if (bytes.get(0) == ValueGetter.NDR.NUMBER) { | |
66 | return new ValueGetter.NDR(bytes); | |
67 | } else { | |
68 | throw new IllegalArgumentException("Unknown Endian type:" + bytes.get(0)); | |
69 | } | |
70 | } | |
71 | ||
72 | /** | |
73 | * Parse a hex encoded geometry | |
74 | * | |
75 | * Is synchronized to protect offset counter. (Unfortunately, Java does not | |
76 | * have neither call by reference nor multiple return values.) | |
77 | * | |
78 | * @param value String containing the data to be parsed | |
79 | * @return resulting geometry for the parsed data | |
80 | */ | |
81 | public synchronized Geometry parse(String value) { | |
82 | StringByteGetter bytes = new StringByteGetter(value); | |
83 | return parseGeometry(valueGetterForEndian(bytes)); | |
84 | } | |
85 | ||
86 | /** | |
87 | * Parse a binary encoded geometry. | |
88 | * | |
89 | * Is synchronized to protect offset counter. (Unfortunately, Java does not | |
90 | * have neither call by reference nor multiple return values.) | |
91 | * | |
92 | * @param value byte array containing the data to be parsed | |
93 | * @return resulting geometry for the parsed data | |
94 | */ | |
95 | public synchronized Geometry parse(byte[] value) { | |
96 | BinaryByteGetter bytes = new BinaryByteGetter(value); | |
97 | return parseGeometry(valueGetterForEndian(bytes)); | |
98 | } | |
99 | ||
100 | /** | |
101 | * Parse a geometry starting at offset. | |
102 | * | |
103 | * @param data ValueGetter with the data to be parsed | |
104 | * @return the parsed geometry | |
105 | * */ | |
106 | protected Geometry parseGeometry(ValueGetter data) { | |
107 | byte endian = data.getByte(); // skip and test endian flag | |
108 | if (endian != data.endian) { | |
109 | throw new IllegalArgumentException("Endian inconsistency!"); | |
110 | } | |
111 | int typeword = data.getInt(); | |
112 | ||
113 | int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits | |
114 | ||
115 | boolean haveZ = (typeword & 0x80000000) != 0; | |
116 | boolean haveM = (typeword & 0x40000000) != 0; | |
117 | boolean haveS = (typeword & 0x20000000) != 0; | |
118 | ||
119 | int srid = Geometry.UNKNOWN_SRID; | |
120 | ||
121 | if (haveS) { | |
122 | srid = Geometry.parseSRID(data.getInt()); | |
123 | } | |
124 | Geometry result1; | |
125 | switch (realtype) { | |
126 | case Geometry.POINT : | |
127 | result1 = parsePoint(data, haveZ, haveM); | |
128 | break; | |
129 | case Geometry.LINESTRING : | |
130 | result1 = parseLineString(data, haveZ, haveM); | |
131 | break; | |
132 | case Geometry.POLYGON : | |
133 | result1 = parsePolygon(data, haveZ, haveM); | |
134 | break; | |
135 | case Geometry.MULTIPOINT : | |
136 | result1 = parseMultiPoint(data); | |
137 | break; | |
138 | case Geometry.MULTILINESTRING : | |
139 | result1 = parseMultiLineString(data); | |
140 | break; | |
141 | case Geometry.MULTIPOLYGON : | |
142 | result1 = parseMultiPolygon(data); | |
143 | break; | |
144 | case Geometry.GEOMETRYCOLLECTION : | |
145 | result1 = parseCollection(data); | |
146 | break; | |
147 | default : | |
148 | throw new IllegalArgumentException("Unknown Geometry Type: " + realtype); | |
149 | } | |
150 | ||
151 | Geometry result = result1; | |
152 | ||
153 | if (srid != Geometry.UNKNOWN_SRID) { | |
154 | result.setSrid(srid); | |
155 | } | |
156 | return result; | |
157 | } | |
158 | ||
159 | private Point parsePoint(ValueGetter data, boolean haveZ, boolean haveM) { | |
160 | double X = data.getDouble(); | |
161 | double Y = data.getDouble(); | |
162 | Point result; | |
163 | if (haveZ) { | |
164 | double Z = data.getDouble(); | |
165 | result = new Point(X, Y, Z); | |
166 | } else { | |
167 | result = new Point(X, Y); | |
168 | } | |
169 | ||
170 | if (haveM) { | |
171 | result.setM(data.getDouble()); | |
172 | } | |
173 | ||
174 | return result; | |
175 | } | |
176 | ||
177 | /** Parse an Array of "full" Geometries */ | |
178 | private void parseGeometryArray(ValueGetter data, Geometry[] container) { | |
179 | for (int i = 0; i < container.length; i++) { | |
180 | container[i] = parseGeometry(data); | |
181 | } | |
182 | } | |
183 | ||
184 | /** | |
185 | * Parse an Array of "slim" Points (without endianness and type, part of | |
186 | * LinearRing and Linestring, but not MultiPoint! | |
187 | * | |
188 | * @param haveZ | |
189 | * @param haveM | |
190 | */ | |
191 | private Point[] parsePointArray(ValueGetter data, boolean haveZ, boolean haveM) { | |
192 | int count = data.getInt(); | |
193 | Point[] result = new Point[count]; | |
194 | for (int i = 0; i < count; i++) { | |
195 | result[i] = parsePoint(data, haveZ, haveM); | |
196 | } | |
197 | return result; | |
198 | } | |
199 | ||
200 | private MultiPoint parseMultiPoint(ValueGetter data) { | |
201 | Point[] points = new Point[data.getInt()]; | |
202 | parseGeometryArray(data, points); | |
203 | return new MultiPoint(points); | |
204 | } | |
205 | ||
206 | private LineString parseLineString(ValueGetter data, boolean haveZ, boolean haveM) { | |
207 | Point[] points = parsePointArray(data, haveZ, haveM); | |
208 | return new LineString(points); | |
209 | } | |
210 | ||
211 | private LinearRing parseLinearRing(ValueGetter data, boolean haveZ, boolean haveM) { | |
212 | Point[] points = parsePointArray(data, haveZ, haveM); | |
213 | return new LinearRing(points); | |
214 | } | |
215 | ||
216 | private Polygon parsePolygon(ValueGetter data, boolean haveZ, boolean haveM) { | |
217 | int count = data.getInt(); | |
218 | LinearRing[] rings = new LinearRing[count]; | |
219 | for (int i = 0; i < count; i++) { | |
220 | rings[i] = parseLinearRing(data, haveZ, haveM); | |
221 | } | |
222 | return new Polygon(rings); | |
223 | } | |
224 | ||
225 | private MultiLineString parseMultiLineString(ValueGetter data) { | |
226 | int count = data.getInt(); | |
227 | LineString[] strings = new LineString[count]; | |
228 | parseGeometryArray(data, strings); | |
229 | return new MultiLineString(strings); | |
230 | } | |
231 | ||
232 | private MultiPolygon parseMultiPolygon(ValueGetter data) { | |
233 | int count = data.getInt(); | |
234 | Polygon[] polys = new Polygon[count]; | |
235 | parseGeometryArray(data, polys); | |
236 | return new MultiPolygon(polys); | |
237 | } | |
238 | ||
239 | private GeometryCollection parseCollection(ValueGetter data) { | |
240 | int count = data.getInt(); | |
241 | Geometry[] geoms = new Geometry[count]; | |
242 | parseGeometryArray(data, geoms); | |
243 | return new GeometryCollection(geoms); | |
244 | } | |
245 | } |
0 | /* | |
1 | * BinaryWriter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Writer | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | package org.postgis.binary; | |
25 | ||
26 | import org.postgis.Geometry; | |
27 | import org.postgis.GeometryCollection; | |
28 | import org.postgis.LineString; | |
29 | import org.postgis.LinearRing; | |
30 | import org.postgis.MultiLineString; | |
31 | import org.postgis.MultiPoint; | |
32 | import org.postgis.MultiPolygon; | |
33 | import org.postgis.Point; | |
34 | import org.postgis.Polygon; | |
35 | ||
36 | ||
37 | /** | |
38 | * Create binary representation of geometries. Currently, only text rep (hexed) | |
39 | * implementation is tested. | |
40 | * | |
41 | * It should be easy to add char[] and CharSequence ByteGetter instances, | |
42 | * although the latter one is not compatible with older jdks. | |
43 | * | |
44 | * I did not implement real unsigned 32-bit integers or emulate them with long, | |
45 | * as both java Arrays and Strings currently can have only 2^31-1 elements | |
46 | * (bytes), so we cannot even get or build Geometries with more than approx. | |
47 | * 2^28 coordinates (8 bytes each). | |
48 | * | |
49 | * @author markus.schaber@logi-track.com | |
50 | * | |
51 | */ | |
52 | public class BinaryWriter { | |
53 | ||
54 | /** | |
55 | * Get the appropriate ValueGetter for my endianness | |
56 | * | |
57 | * @param bytes The ByteSetter to use | |
58 | * @param endian the endian for the ValueSetter to use | |
59 | * @return the ValueGetter | |
60 | */ | |
61 | public static ValueSetter valueSetterForEndian(ByteSetter bytes, byte endian) { | |
62 | if (endian == ValueSetter.XDR.NUMBER) { // XDR | |
63 | return new ValueSetter.XDR(bytes); | |
64 | } else if (endian == ValueSetter.NDR.NUMBER) { | |
65 | return new ValueSetter.NDR(bytes); | |
66 | } else { | |
67 | throw new IllegalArgumentException("Unknown Endian type:" + endian); | |
68 | } | |
69 | } | |
70 | ||
71 | /** | |
72 | * Write a hex encoded geometry | |
73 | * | |
74 | * Is synchronized to protect offset counter. (Unfortunately, Java does not | |
75 | * have neither call by reference nor multiple return values.) This is a | |
76 | * TODO item. | |
77 | * | |
78 | * The geometry you put in must be consistent, geom.checkConsistency() must | |
79 | * return true. If not, the result may be invalid WKB. | |
80 | * | |
81 | * @see Geometry#checkConsistency() the consistency checker | |
82 | * | |
83 | * @param geom the geometry to be written | |
84 | * @param REP endianness to write the bytes with | |
85 | * @return String containing the hex encoded geometry | |
86 | */ | |
87 | public synchronized String writeHexed(Geometry geom, byte REP) { | |
88 | int length = estimateBytes(geom); | |
89 | ByteSetter.StringByteSetter bytes = new ByteSetter.StringByteSetter(length); | |
90 | writeGeometry(geom, valueSetterForEndian(bytes, REP)); | |
91 | return bytes.result(); | |
92 | } | |
93 | ||
94 | public synchronized String writeHexed(Geometry geom) { | |
95 | return writeHexed(geom, ValueSetter.NDR.NUMBER); | |
96 | } | |
97 | ||
98 | /** | |
99 | * Write a binary encoded geometry. | |
100 | * | |
101 | * Is synchronized to protect offset counter. (Unfortunately, Java does not | |
102 | * have neither call by reference nor multiple return values.) This is a | |
103 | * TODO item. | |
104 | * | |
105 | * The geometry you put in must be consistent, geom.checkConsistency() must | |
106 | * return true. If not, the result may be invalid WKB. | |
107 | * | |
108 | * @see Geometry#checkConsistency() | |
109 | * | |
110 | * @param geom the geometry to be written | |
111 | * @param REP endianness to write the bytes with | |
112 | * @return byte array containing the encoded geometry | |
113 | */ | |
114 | public synchronized byte[] writeBinary(Geometry geom, byte REP) { | |
115 | int length = estimateBytes(geom); | |
116 | ByteSetter.BinaryByteSetter bytes = new ByteSetter.BinaryByteSetter(length); | |
117 | writeGeometry(geom, valueSetterForEndian(bytes, REP)); | |
118 | return bytes.result(); | |
119 | } | |
120 | ||
121 | public synchronized byte[] writeBinary(Geometry geom) { | |
122 | return writeBinary(geom, ValueSetter.NDR.NUMBER); | |
123 | } | |
124 | ||
125 | /** | |
126 | * Parse a geometry starting at offset. | |
127 | * @param geom the geometry to write | |
128 | * @param dest the value setting to be used for writing | |
129 | */ | |
130 | protected void writeGeometry(Geometry geom, ValueSetter dest) { | |
131 | // write endian flag | |
132 | dest.setByte(dest.endian); | |
133 | ||
134 | // write typeword | |
135 | int typeword = geom.type; | |
136 | if (geom.dimension == 3) { | |
137 | typeword |= 0x80000000; | |
138 | } | |
139 | if (geom.haveMeasure) { | |
140 | typeword |= 0x40000000; | |
141 | } | |
142 | if (geom.srid != Geometry.UNKNOWN_SRID) { | |
143 | typeword |= 0x20000000; | |
144 | } | |
145 | ||
146 | dest.setInt(typeword); | |
147 | ||
148 | if (geom.srid != Geometry.UNKNOWN_SRID) { | |
149 | dest.setInt(geom.srid); | |
150 | } | |
151 | ||
152 | switch (geom.type) { | |
153 | case Geometry.POINT : | |
154 | writePoint((Point) geom, dest); | |
155 | break; | |
156 | case Geometry.LINESTRING : | |
157 | writeLineString((LineString) geom, dest); | |
158 | break; | |
159 | case Geometry.POLYGON : | |
160 | writePolygon((Polygon) geom, dest); | |
161 | break; | |
162 | case Geometry.MULTIPOINT : | |
163 | writeMultiPoint((MultiPoint) geom, dest); | |
164 | break; | |
165 | case Geometry.MULTILINESTRING : | |
166 | writeMultiLineString((MultiLineString) geom, dest); | |
167 | break; | |
168 | case Geometry.MULTIPOLYGON : | |
169 | writeMultiPolygon((MultiPolygon) geom, dest); | |
170 | break; | |
171 | case Geometry.GEOMETRYCOLLECTION : | |
172 | writeCollection((GeometryCollection) geom, dest); | |
173 | break; | |
174 | default : | |
175 | throw new IllegalArgumentException("Unknown Geometry Type: " + geom.type); | |
176 | } | |
177 | } | |
178 | ||
179 | /** | |
180 | * Writes a "slim" Point (without endiannes, srid ant type, only the | |
181 | * ordinates and measure. Used by writeGeometry as ell as writePointArray. | |
182 | */ | |
183 | private void writePoint(Point geom, ValueSetter dest) { | |
184 | dest.setDouble(geom.x); | |
185 | dest.setDouble(geom.y); | |
186 | ||
187 | if (geom.dimension == 3) { | |
188 | dest.setDouble(geom.z); | |
189 | } | |
190 | ||
191 | if (geom.haveMeasure) { | |
192 | dest.setDouble(geom.m); | |
193 | } | |
194 | } | |
195 | ||
196 | /** Write an Array of "full" Geometries */ | |
197 | private void writeGeometryArray(Geometry[] container, ValueSetter dest) { | |
198 | for (int i = 0; i < container.length; i++) { | |
199 | writeGeometry(container[i], dest); | |
200 | } | |
201 | } | |
202 | ||
203 | /** | |
204 | * Write an Array of "slim" Points (without endianness, srid and type, part | |
205 | * of LinearRing and Linestring, but not MultiPoint! | |
206 | */ | |
207 | private void writePointArray(Point[] geom, ValueSetter dest) { | |
208 | // number of points | |
209 | dest.setInt(geom.length); | |
210 | for (int i = 0; i < geom.length; i++) { | |
211 | writePoint(geom[i], dest); | |
212 | } | |
213 | } | |
214 | ||
215 | private void writeMultiPoint(MultiPoint geom, ValueSetter dest) { | |
216 | dest.setInt(geom.numPoints()); | |
217 | writeGeometryArray(geom.getPoints(), dest); | |
218 | } | |
219 | ||
220 | private void writeLineString(LineString geom, ValueSetter dest) { | |
221 | writePointArray(geom.getPoints(), dest); | |
222 | } | |
223 | ||
224 | private void writeLinearRing(LinearRing geom, ValueSetter dest) { | |
225 | writePointArray(geom.getPoints(), dest); | |
226 | } | |
227 | ||
228 | private void writePolygon(Polygon geom, ValueSetter dest) { | |
229 | dest.setInt(geom.numRings()); | |
230 | for (int i = 0; i < geom.numRings(); i++) { | |
231 | writeLinearRing(geom.getRing(i), dest); | |
232 | } | |
233 | } | |
234 | ||
235 | private void writeMultiLineString(MultiLineString geom, ValueSetter dest) { | |
236 | dest.setInt(geom.numLines()); | |
237 | writeGeometryArray(geom.getLines(), dest); | |
238 | } | |
239 | ||
240 | private void writeMultiPolygon(MultiPolygon geom, ValueSetter dest) { | |
241 | dest.setInt(geom.numPolygons()); | |
242 | writeGeometryArray(geom.getPolygons(), dest); | |
243 | } | |
244 | ||
245 | private void writeCollection(GeometryCollection geom, ValueSetter dest) { | |
246 | dest.setInt(geom.numGeoms()); | |
247 | writeGeometryArray(geom.getGeometries(), dest); | |
248 | } | |
249 | ||
250 | /** | |
251 | * Estimate how much bytes a geometry will need in WKB. | |
252 | * | |
253 | * @param geom Geometry to estimate. | |
254 | * @return estimated number of bytes | |
255 | */ | |
256 | protected int estimateBytes(Geometry geom) { | |
257 | int result = 0; | |
258 | ||
259 | // write endian flag | |
260 | result += 1; | |
261 | ||
262 | // write typeword | |
263 | result += 4; | |
264 | ||
265 | if (geom.srid != Geometry.UNKNOWN_SRID) { | |
266 | result += 4; | |
267 | } | |
268 | ||
269 | switch (geom.type) { | |
270 | case Geometry.POINT : | |
271 | result += estimatePoint((Point) geom); | |
272 | break; | |
273 | case Geometry.LINESTRING : | |
274 | result += estimateLineString((LineString) geom); | |
275 | break; | |
276 | case Geometry.POLYGON : | |
277 | result += estimatePolygon((Polygon) geom); | |
278 | break; | |
279 | case Geometry.MULTIPOINT : | |
280 | result += estimateMultiPoint((MultiPoint) geom); | |
281 | break; | |
282 | case Geometry.MULTILINESTRING : | |
283 | result += estimateMultiLineString((MultiLineString) geom); | |
284 | break; | |
285 | case Geometry.MULTIPOLYGON : | |
286 | result += estimateMultiPolygon((MultiPolygon) geom); | |
287 | break; | |
288 | case Geometry.GEOMETRYCOLLECTION : | |
289 | result += estimateCollection((GeometryCollection) geom); | |
290 | break; | |
291 | default : | |
292 | throw new IllegalArgumentException("Unknown Geometry Type: " + geom.type); | |
293 | } | |
294 | return result; | |
295 | } | |
296 | ||
297 | private int estimatePoint(Point geom) { | |
298 | // x, y both have 8 bytes | |
299 | int result = 16; | |
300 | if (geom.dimension == 3) { | |
301 | result += 8; | |
302 | } | |
303 | ||
304 | if (geom.haveMeasure) { | |
305 | result += 8; | |
306 | } | |
307 | return result; | |
308 | } | |
309 | ||
310 | /** Write an Array of "full" Geometries */ | |
311 | private int estimateGeometryArray(Geometry[] container) { | |
312 | int result = 0; | |
313 | for (int i = 0; i < container.length; i++) { | |
314 | result += estimateBytes(container[i]); | |
315 | } | |
316 | return result; | |
317 | } | |
318 | ||
319 | /** | |
320 | * Write an Array of "slim" Points (without endianness and type, part of | |
321 | * LinearRing and Linestring, but not MultiPoint! | |
322 | */ | |
323 | private int estimatePointArray(Point[] geom) { | |
324 | // number of points | |
325 | int result = 4; | |
326 | ||
327 | // And the amount of the points itsself, in consistent geometries | |
328 | // all points have equal size. | |
329 | if (geom.length > 0) { | |
330 | result += geom.length * estimatePoint(geom[0]); | |
331 | } | |
332 | return result; | |
333 | } | |
334 | ||
335 | private int estimateMultiPoint(MultiPoint geom) { | |
336 | // int size | |
337 | int result = 4; | |
338 | if (geom.numPoints() > 0) { | |
339 | // We can shortcut here, as all subgeoms have the same fixed size | |
340 | result += geom.numPoints() * estimateBytes(geom.getFirstPoint()); | |
341 | } | |
342 | return result; | |
343 | } | |
344 | ||
345 | private int estimateLineString(LineString geom) { | |
346 | return estimatePointArray(geom.getPoints()); | |
347 | } | |
348 | ||
349 | private int estimateLinearRing(LinearRing geom) { | |
350 | return estimatePointArray(geom.getPoints()); | |
351 | } | |
352 | ||
353 | private int estimatePolygon(Polygon geom) { | |
354 | // int length | |
355 | int result = 4; | |
356 | for (int i = 0; i < geom.numRings(); i++) { | |
357 | result += estimateLinearRing(geom.getRing(i)); | |
358 | } | |
359 | return result; | |
360 | } | |
361 | ||
362 | private int estimateMultiLineString(MultiLineString geom) { | |
363 | // 4-byte count + subgeometries | |
364 | return 4 + estimateGeometryArray(geom.getLines()); | |
365 | } | |
366 | ||
367 | private int estimateMultiPolygon(MultiPolygon geom) { | |
368 | // 4-byte count + subgeometries | |
369 | return 4 + estimateGeometryArray(geom.getPolygons()); | |
370 | } | |
371 | ||
372 | private int estimateCollection(GeometryCollection geom) { | |
373 | // 4-byte count + subgeometries | |
374 | return 4 + estimateGeometryArray(geom.getGeometries()); | |
375 | } | |
376 | } |
0 | /* | |
1 | * ByteGetter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Parser | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package org.postgis.binary; | |
26 | ||
27 | public abstract class ByteGetter { | |
28 | /** | |
29 | * Get a byte. | |
30 | * | |
31 | * @param index the index to get the value from | |
32 | * @return The result is returned as Int to eliminate sign problems when | |
33 | * or'ing several values together. | |
34 | */ | |
35 | public abstract int get(int index); | |
36 | ||
37 | public static class BinaryByteGetter extends ByteGetter { | |
38 | private byte[] array; | |
39 | ||
40 | public BinaryByteGetter(byte[] array) { | |
41 | this.array = array; | |
42 | } | |
43 | ||
44 | public int get(int index) { | |
45 | return array[index] & 0xFF; // mask out sign-extended bits. | |
46 | } | |
47 | } | |
48 | ||
49 | public static class StringByteGetter extends ByteGetter { | |
50 | private String rep; | |
51 | ||
52 | public StringByteGetter(String rep) { | |
53 | this.rep = rep; | |
54 | } | |
55 | ||
56 | public int get(int index) { | |
57 | index *= 2; | |
58 | int high = unhex(rep.charAt(index)); | |
59 | int low = unhex(rep.charAt(index + 1)); | |
60 | return (high << 4) + low; | |
61 | } | |
62 | ||
63 | public static byte unhex(char c) { | |
64 | if (c >= '0' && c <= '9') { | |
65 | return (byte) (c - '0'); | |
66 | } else if (c >= 'A' && c <= 'F') { | |
67 | return (byte) (c - 'A' + 10); | |
68 | } else if (c >= 'a' && c <= 'f') { | |
69 | return (byte) (c - 'a' + 10); | |
70 | } else { | |
71 | throw new IllegalArgumentException("No valid Hex char " + c); | |
72 | } | |
73 | } | |
74 | } | |
75 | } |
0 | /* | |
1 | * ByteSetter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Parser | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package org.postgis.binary; | |
26 | ||
27 | public abstract class ByteSetter { | |
28 | ||
29 | /** | |
30 | * Set a byte. | |
31 | * | |
32 | * @param b byte value to set with | |
33 | * @param index index to set | |
34 | */ | |
35 | public abstract void set(byte b, int index); | |
36 | ||
37 | public static class BinaryByteSetter extends ByteSetter { | |
38 | private byte[] array; | |
39 | ||
40 | public BinaryByteSetter(int length) { | |
41 | this.array = new byte[length]; | |
42 | } | |
43 | ||
44 | public void set(byte b, int index) { | |
45 | array[index] = b; // mask out sign-extended bits. | |
46 | } | |
47 | ||
48 | public byte[] result() { | |
49 | return array; | |
50 | } | |
51 | ||
52 | public String toString() { | |
53 | char[] arr = new char[array.length]; | |
54 | for (int i=0; i<array.length; i++) { | |
55 | arr[i] = (char)(array[i]&0xFF); | |
56 | } | |
57 | return new String(arr); | |
58 | } | |
59 | } | |
60 | ||
61 | public static class StringByteSetter extends ByteSetter { | |
62 | protected static final char[] hextypes = "0123456789ABCDEF".toCharArray(); | |
63 | private char[] rep; | |
64 | ||
65 | public StringByteSetter(int length) { | |
66 | this.rep = new char[length * 2]; | |
67 | } | |
68 | ||
69 | public void set(byte b, int index) { | |
70 | index *= 2; | |
71 | rep[index] = hextypes[(b >>> 4) & 0xF]; | |
72 | rep[index + 1] = hextypes[b & 0xF]; | |
73 | } | |
74 | ||
75 | public char[] resultAsArray() { | |
76 | return rep; | |
77 | } | |
78 | ||
79 | public String result() { | |
80 | return new String(rep); | |
81 | } | |
82 | ||
83 | public String toString() { | |
84 | return new String(rep); | |
85 | } | |
86 | } | |
87 | } |
0 | /* | |
1 | * ValueGetter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Parser | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package org.postgis.binary; | |
26 | ||
27 | public abstract class ValueGetter { | |
28 | ByteGetter data; | |
29 | int position; | |
30 | public final byte endian; | |
31 | ||
32 | public ValueGetter(ByteGetter data, byte endian) { | |
33 | this.data = data; | |
34 | this.endian = endian; | |
35 | } | |
36 | ||
37 | /** | |
38 | * Get a byte, should be equal for all endians | |
39 | * | |
40 | * @return the byte value | |
41 | */ | |
42 | public byte getByte() { | |
43 | return (byte) data.get(position++); | |
44 | } | |
45 | ||
46 | public int getInt() { | |
47 | int res = getInt(position); | |
48 | position += 4; | |
49 | return res; | |
50 | } | |
51 | ||
52 | public long getLong() { | |
53 | long res = getLong(position); | |
54 | position += 8; | |
55 | return res; | |
56 | } | |
57 | ||
58 | /** | |
59 | * Get a 32-Bit integer | |
60 | * | |
61 | * @param index the index to get the value from | |
62 | * @return the int value | |
63 | */ | |
64 | protected abstract int getInt(int index); | |
65 | ||
66 | /** | |
67 | * Get a long value. This is not needed directly, but as a nice side-effect | |
68 | * from GetDouble. | |
69 | * | |
70 | * @param index the index to get the value from | |
71 | * @return the long value | |
72 | */ | |
73 | protected abstract long getLong(int index); | |
74 | ||
75 | /** | |
76 | * Get a double. | |
77 | * | |
78 | * @return the double value | |
79 | */ | |
80 | public double getDouble() { | |
81 | long bitrep = getLong(); | |
82 | return Double.longBitsToDouble(bitrep); | |
83 | } | |
84 | ||
85 | public static class XDR extends ValueGetter { | |
86 | public static final byte NUMBER = 0; | |
87 | ||
88 | public XDR(ByteGetter data) { | |
89 | super(data, NUMBER); | |
90 | } | |
91 | ||
92 | protected int getInt(int index) { | |
93 | return (data.get(index) << 24) + (data.get(index + 1) << 16) | |
94 | + (data.get(index + 2) << 8) + data.get(index + 3); | |
95 | } | |
96 | ||
97 | protected long getLong(int index) { | |
98 | return ((long) data.get(index) << 56) + ((long) data.get(index + 1) << 48) | |
99 | + ((long) data.get(index + 2) << 40) + ((long) data.get(index + 3) << 32) | |
100 | + ((long) data.get(index + 4) << 24) + ((long) data.get(index + 5) << 16) | |
101 | + ((long) data.get(index + 6) << 8) + ((long) data.get(index + 7) << 0); | |
102 | } | |
103 | } | |
104 | ||
105 | public static class NDR extends ValueGetter { | |
106 | public static final byte NUMBER = 1; | |
107 | ||
108 | public NDR(ByteGetter data) { | |
109 | super(data, NUMBER); | |
110 | } | |
111 | ||
112 | protected int getInt(int index) { | |
113 | return (data.get(index + 3) << 24) + (data.get(index + 2) << 16) | |
114 | + (data.get(index + 1) << 8) + data.get(index); | |
115 | } | |
116 | ||
117 | protected long getLong(int index) { | |
118 | return ((long) data.get(index + 7) << 56) + ((long) data.get(index + 6) << 48) | |
119 | + ((long) data.get(index + 5) << 40) + ((long) data.get(index + 4) << 32) | |
120 | + ((long) data.get(index + 3) << 24) + ((long) data.get(index + 2) << 16) | |
121 | + ((long) data.get(index + 1) << 8) + ((long) data.get(index) << 0); | |
122 | } | |
123 | } | |
124 | } |
0 | /* | |
1 | * ValueSetter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Parser | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package org.postgis.binary; | |
26 | ||
27 | public abstract class ValueSetter { | |
28 | ByteSetter data; | |
29 | int position=0; | |
30 | public final byte endian; | |
31 | ||
32 | public ValueSetter(ByteSetter data, byte endian) { | |
33 | this.data = data; | |
34 | this.endian = endian; | |
35 | } | |
36 | ||
37 | /** | |
38 | * Set a byte, should be equal for all endians | |
39 | * | |
40 | * @param value byte value to be set with. | |
41 | */ | |
42 | public void setByte(byte value) { | |
43 | data.set(value, position); | |
44 | position += 1; | |
45 | } | |
46 | ||
47 | public void setInt(int value) { | |
48 | setInt(value, position); | |
49 | position += 4; | |
50 | } | |
51 | ||
52 | public void setLong(long value) { | |
53 | setLong(value, position); | |
54 | position += 8; | |
55 | } | |
56 | ||
57 | /** | |
58 | * Set a 32-Bit integer | |
59 | * | |
60 | * @param value int value to be set with | |
61 | * @param index int value for the index | |
62 | * | |
63 | */ | |
64 | protected abstract void setInt(int value, int index); | |
65 | ||
66 | /** | |
67 | * Set a long value. This is not needed directly, but as a nice side-effect | |
68 | * from GetDouble. | |
69 | * | |
70 | * @param data int value to be set with | |
71 | * @param index int value for the index | |
72 | */ | |
73 | protected abstract void setLong(long data, int index); | |
74 | ||
75 | /** | |
76 | * Set a double. | |
77 | * | |
78 | * @param data double value to be set with | |
79 | */ | |
80 | public void setDouble(double data) { | |
81 | long bitrep = Double.doubleToLongBits(data); | |
82 | setLong(bitrep); | |
83 | } | |
84 | ||
85 | public String toString() { | |
86 | String name = getClass().getName(); | |
87 | int pointpos = name.lastIndexOf('.'); | |
88 | String klsName = name.substring(pointpos+1); | |
89 | return klsName+"('"+(data==null?"NULL":data.toString()+"')"); | |
90 | } | |
91 | ||
92 | public static class XDR extends ValueSetter { | |
93 | public static final byte NUMBER = 0; | |
94 | ||
95 | public XDR(ByteSetter data) { | |
96 | super(data, NUMBER); | |
97 | } | |
98 | ||
99 | protected void setInt(int value, int index) { | |
100 | data.set((byte) (value >>> 24), index); | |
101 | data.set((byte) (value >>> 16), index + 1); | |
102 | data.set((byte) (value >>> 8), index + 2); | |
103 | data.set((byte) value, index + 3); | |
104 | } | |
105 | ||
106 | protected void setLong(long value, int index) { | |
107 | data.set((byte) (value >>> 56), index); | |
108 | data.set((byte) (value >>> 48), index + 1); | |
109 | data.set((byte) (value >>> 40), index + 2); | |
110 | data.set((byte) (value >>> 32), index + 3); | |
111 | data.set((byte) (value >>> 24), index + 4); | |
112 | data.set((byte) (value >>> 16), index + 5); | |
113 | data.set((byte) (value >>> 8), index + 6); | |
114 | data.set((byte) value, index + 7); | |
115 | } | |
116 | } | |
117 | ||
118 | public static class NDR extends ValueSetter { | |
119 | public static final byte NUMBER = 1; | |
120 | ||
121 | public NDR(ByteSetter data) { | |
122 | super(data, NUMBER); | |
123 | } | |
124 | ||
125 | protected void setInt(int value, int index) { | |
126 | data.set((byte) (value >>> 24), index + 3); | |
127 | data.set((byte) (value >>> 16), index + 2); | |
128 | data.set((byte) (value >>> 8), index + 1); | |
129 | data.set((byte) value, index); | |
130 | } | |
131 | ||
132 | protected void setLong(long value, int index) { | |
133 | data.set((byte) (value >>> 56), index + 7); | |
134 | data.set((byte) (value >>> 48), index + 6); | |
135 | data.set((byte) (value >>> 40), index + 5); | |
136 | data.set((byte) (value >>> 32), index + 4); | |
137 | data.set((byte) (value >>> 24), index + 3); | |
138 | data.set((byte) (value >>> 16), index + 2); | |
139 | data.set((byte) (value >>> 8), index + 1); | |
140 | data.set((byte) value, index); | |
141 | } | |
142 | } | |
143 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2020 Phillip Ross, phillip.w.g.ross@gmail.com | |
16 | */ | |
17 | ||
18 | package org.postgis.util; | |
19 | ||
20 | ||
21 | /** | |
22 | * An enumeration of existing version functions. | |
23 | * | |
24 | * @author Phillip Ross | |
25 | */ | |
26 | public enum VersionFunctions { | |
27 | ||
28 | /** The function to return the full version and build configuration info of the PostGIS Server. */ | |
29 | POSTGIS_FULL_VERSION, | |
30 | ||
31 | /** The function to return the version of the GDAL library. */ | |
32 | POSTGIS_GDAL_VERSION, | |
33 | ||
34 | /** The function to return the version of the GEOS library. */ | |
35 | POSTGIS_GEOS_VERSION, | |
36 | ||
37 | /** The function to return the build date of the PostGIS library. */ | |
38 | POSTGIS_LIB_BUILD_DATE, | |
39 | ||
40 | /** The function to return the version of the PostGIS library. */ | |
41 | POSTGIS_LIB_VERSION, | |
42 | ||
43 | /** The function to return the version of the libjson library. */ | |
44 | POSTGIS_LIBJSON_VERSION, | |
45 | ||
46 | /** The function to return the version of the libxml library. */ | |
47 | POSTGIS_LIBXML_VERSION, | |
48 | ||
49 | /** The function to return the version of the Proj library. */ | |
50 | POSTGIS_PROJ_VERSION, | |
51 | ||
52 | /** The function to return the version of the raster library. */ | |
53 | POSTGIS_RASTER_LIB_VERSION, | |
54 | ||
55 | /** The function to return the build date of the scripts. */ | |
56 | POSTGIS_SCRIPTS_BUILD_DATE, | |
57 | ||
58 | /** The function to return the version of the scripts installed in the database. */ | |
59 | POSTGIS_SCRIPTS_INSTALLED, | |
60 | ||
61 | /** The function to return the version of the scripts released with the installed PostGIS library. */ | |
62 | POSTGIS_SCRIPTS_RELEASED, | |
63 | ||
64 | /** The function to return the Subversion version of the PostGIS Server. */ | |
65 | POSTGIS_SVN_VERSION, | |
66 | ||
67 | /** The function to return the version of the PostGIS Server. */ | |
68 | POSTGIS_VERSION | |
69 | ||
70 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2020 Phillip Ross, phillip.w.g.ross@gmail.com | |
16 | */ | |
17 | ||
18 | package org.postgis.util; | |
19 | ||
20 | ||
21 | import org.slf4j.Logger; | |
22 | import org.slf4j.LoggerFactory; | |
23 | ||
24 | import java.sql.Connection; | |
25 | import java.sql.PreparedStatement; | |
26 | import java.sql.ResultSet; | |
27 | import java.sql.SQLException; | |
28 | import java.util.Objects; | |
29 | ||
30 | ||
31 | /** | |
32 | * Utility for working with PostGIS Server version. | |
33 | * | |
34 | * @author Phillip Ross | |
35 | */ | |
36 | public class VersionUtil { | |
37 | ||
38 | /** The static logger instance. */ | |
39 | private static final Logger logger = LoggerFactory.getLogger(VersionUtil.class); | |
40 | ||
41 | /** The string to match when determining a function does not exist from the content of an error message. */ | |
42 | public static final String NONEXISTENT_FUNCTION_ERROR_MESSAGE_CONTENT = "does not exist"; | |
43 | ||
44 | /** The token which separates version components within the PostGIS Server version. */ | |
45 | public static final String POSTGIS_SERVER_VERSION_SEPERATOR = "."; | |
46 | ||
47 | /** The number of seconds to wait for a connection validation operation. */ | |
48 | private static final int DEFAULT_CONNECTION_TIMEOUT = 60; | |
49 | ||
50 | ||
51 | /** | |
52 | * Query a specific version string from the datasource for a specified function. | |
53 | * | |
54 | * @param connection The connection to issue the version query function against. | |
55 | * @param function The version function to use for querying the version. | |
56 | * @return a string version for the specified function. | |
57 | * @throws SQLException when a jdbc exception occurs. | |
58 | */ | |
59 | public static String getVersionString(final Connection connection, final String function) throws SQLException { | |
60 | Objects.requireNonNull(connection, "Unable to retrieve version string from a null connection"); | |
61 | Objects.requireNonNull(function, "Unable to retrieve version string for a null function"); | |
62 | validateConnection(connection); | |
63 | ||
64 | String result = "-- unavailable -- "; | |
65 | try ( | |
66 | PreparedStatement statement = connection.prepareStatement("SELECT " + function + "()"); | |
67 | ResultSet resultSet = statement.executeQuery(); | |
68 | ) { | |
69 | if (resultSet.next()) { | |
70 | String version = resultSet.getString(1); | |
71 | if (version != null) { | |
72 | result = version.trim(); | |
73 | } else { | |
74 | result = "-- null result --"; | |
75 | } | |
76 | } else { | |
77 | result = "-- no result --"; | |
78 | } | |
79 | } catch (SQLException sqle) { | |
80 | // If the function does not exist, a SQLException will be thrown, but it should be caught and swallowed if | |
81 | // the non-existent function error message content is found in the error message. The SQLException might | |
82 | // be thrown for some other problem not related to the missing function, so rethrow it if it doesn't | |
83 | // contain the non-existent function error message content. | |
84 | if (!sqle.getMessage().contains(NONEXISTENT_FUNCTION_ERROR_MESSAGE_CONTENT)) { | |
85 | throw sqle; | |
86 | } | |
87 | } | |
88 | return result; | |
89 | } | |
90 | ||
91 | ||
92 | public static String retrievePostGISServerVersionString(final Connection connection) throws SQLException { | |
93 | Objects.requireNonNull( | |
94 | connection, "Unable to retrieve PostGIS server version string from a null connection" | |
95 | ); | |
96 | validateConnection(connection); | |
97 | String postGISVersionString = getVersionString(connection, VersionFunctions.POSTGIS_VERSION.toString()); | |
98 | logger.debug("retrieved PostGIS server version string: [{}]", postGISVersionString); | |
99 | return postGISVersionString; | |
100 | } | |
101 | ||
102 | ||
103 | public static String retrievePostGISServerVersion(final Connection connection) throws SQLException { | |
104 | Objects.requireNonNull(connection, "Unable to retrieve PostGIS version from a null connection"); | |
105 | validateConnection(connection); | |
106 | String versionString = retrievePostGISServerVersionString(connection); | |
107 | ||
108 | final String versionTerminatorString = " "; | |
109 | final String version; | |
110 | final int versionTerminatorIndex = versionString.indexOf(versionTerminatorString); | |
111 | if (versionTerminatorIndex == -1) { | |
112 | version = versionString; | |
113 | } else { | |
114 | version = versionString.substring(0, versionTerminatorIndex); | |
115 | } | |
116 | logger.debug("retrieved PostGIS server version: [{}]", version); | |
117 | return version; | |
118 | } | |
119 | ||
120 | ||
121 | public static String retrievePostGISServerMajorVersion(final Connection connection) throws SQLException { | |
122 | Objects.requireNonNull(connection, "Unable to retrieve PostGIS major version from a null connection"); | |
123 | validateConnection(connection); | |
124 | String version = retrievePostGISServerVersion(connection); | |
125 | final String majorVersion; | |
126 | final int majorVersionSeperatorIndex = version.indexOf(POSTGIS_SERVER_VERSION_SEPERATOR); | |
127 | if (majorVersionSeperatorIndex == -1) { | |
128 | majorVersion = version; | |
129 | } else { | |
130 | majorVersion = version.substring(0, majorVersionSeperatorIndex); | |
131 | } | |
132 | logger.debug("retrieved postGIS major version string: [{}]", majorVersion); | |
133 | return majorVersion; | |
134 | } | |
135 | ||
136 | ||
137 | public static String retrievePostGISServerMinorVersion(final Connection connection) throws SQLException { | |
138 | Objects.requireNonNull(connection, "Unable to retrieve PostGIS minor version from a null connection"); | |
139 | validateConnection(connection); | |
140 | String version = retrievePostGISServerVersion(connection); | |
141 | final String minorVersion; | |
142 | final int majorVersionSeperatorIndex = version.indexOf(POSTGIS_SERVER_VERSION_SEPERATOR); | |
143 | if (majorVersionSeperatorIndex == -1) { | |
144 | minorVersion = ""; | |
145 | } else { | |
146 | final int minorVersionSeperatorIndex = | |
147 | version.indexOf(POSTGIS_SERVER_VERSION_SEPERATOR, majorVersionSeperatorIndex + 1); | |
148 | if (minorVersionSeperatorIndex == -1) { | |
149 | minorVersion = version.substring(majorVersionSeperatorIndex + 1); | |
150 | } else { | |
151 | minorVersion = version.substring(majorVersionSeperatorIndex + 1, minorVersionSeperatorIndex); | |
152 | } | |
153 | } | |
154 | logger.debug("retrieved postGIS minor version string: [{}]", minorVersion); | |
155 | return minorVersion; | |
156 | } | |
157 | ||
158 | ||
159 | /** | |
160 | * Validates a connection. | |
161 | * | |
162 | * @param connection the connection to be validated. | |
163 | * @throws SQLException when connection is invalid | |
164 | */ | |
165 | private static void validateConnection(final Connection connection) throws SQLException { | |
166 | if (!connection.isValid(DEFAULT_CONNECTION_TIMEOUT)) { | |
167 | throw new SQLException("The connection was not valid."); | |
168 | } | |
169 | } | |
170 | ||
171 | ||
172 | } |
0 | /* | |
1 | * DatatypesTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package org.postgis; | |
28 | ||
29 | ||
30 | import org.slf4j.Logger; | |
31 | import org.slf4j.LoggerFactory; | |
32 | import org.testng.annotations.Test; | |
33 | ||
34 | import java.sql.SQLException; | |
35 | ||
36 | ||
37 | public class DatatypesTest { | |
38 | ||
39 | private static final Logger logger = LoggerFactory.getLogger(DatatypesTest.class); | |
40 | ||
41 | private static final String mlng_str = "MULTILINESTRING ((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"; | |
42 | ||
43 | private static final String mplg_str = "MULTIPOLYGON (((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"; | |
44 | ||
45 | private static final String plg_str = "POLYGON ((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"; | |
46 | ||
47 | private static final String lng_str = "LINESTRING (10 10 20,20 20 20, 50 50 50, 34 34 34)"; | |
48 | ||
49 | private static final String ptg_str = "POINT(10 10 20)"; | |
50 | ||
51 | private static final String lr_str = "(10 10 20,34 34 34, 23 19 23 , 10 10 11)"; | |
52 | ||
53 | ||
54 | @Test | |
55 | public void testLinearRing() throws SQLException { | |
56 | logger.trace("void testLinearRing()"); | |
57 | logger.info(lr_str); | |
58 | LinearRing lr = new LinearRing(lr_str); | |
59 | logger.info(lr.toString()); | |
60 | } | |
61 | ||
62 | ||
63 | @Test | |
64 | public void testPoint() throws SQLException { | |
65 | logger.trace("void testPoint()"); | |
66 | logger.info(ptg_str); | |
67 | Point ptg = new Point(ptg_str); | |
68 | logger.info(ptg.toString()); | |
69 | } | |
70 | ||
71 | ||
72 | @Test | |
73 | public void testLineString() throws SQLException { | |
74 | logger.trace("void testLineString()"); | |
75 | logger.info(lng_str); | |
76 | LineString lng = new LineString(lng_str); | |
77 | logger.info(lng.toString()); | |
78 | } | |
79 | ||
80 | ||
81 | @Test | |
82 | public void testPolygon() throws SQLException { | |
83 | logger.trace("void testPolygon()"); | |
84 | logger.info(plg_str); | |
85 | Polygon plg = new Polygon(plg_str); | |
86 | logger.info(plg.toString()); | |
87 | } | |
88 | ||
89 | ||
90 | @Test | |
91 | public void testMultiPolygon() throws SQLException { | |
92 | logger.trace("void testMultiPolygon()"); | |
93 | logger.info(mplg_str); | |
94 | MultiPolygon mplg = new MultiPolygon(mplg_str); | |
95 | logger.info(mplg.toString()); | |
96 | } | |
97 | ||
98 | ||
99 | @Test | |
100 | public void testMultiLineString() throws SQLException { | |
101 | logger.trace("void testMultiLineString()"); | |
102 | logger.info(mlng_str); | |
103 | MultiLineString mlng = new MultiLineString(mlng_str); | |
104 | logger.info(mlng.toString()); | |
105 | } | |
106 | ||
107 | ||
108 | }⏎ |
0 | /* | |
1 | * TokenizerTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | * | |
21 | */ | |
22 | ||
23 | package org.postgis; | |
24 | ||
25 | import org.slf4j.Logger; | |
26 | import org.slf4j.LoggerFactory; | |
27 | import org.testng.annotations.Test; | |
28 | ||
29 | import java.util.List; | |
30 | ||
31 | ||
32 | public class TokenizerTest { | |
33 | ||
34 | private static final Logger logger = LoggerFactory.getLogger(TokenizerTest.class); | |
35 | ||
36 | ||
37 | @Test | |
38 | public void testTokenizer() { | |
39 | char delimiterL1 = ','; | |
40 | char delimiterL2 = ' '; | |
41 | String stringToTokenize = "((1 2 3),(4 5 6),(7 8 9)"; | |
42 | logger.debug("tokenizing string value => {}", stringToTokenize); | |
43 | List<String> tokensLevel1 = GeometryTokenizer.tokenize(GeometryTokenizer.removeLeadingAndTrailingStrings(stringToTokenize, "(", ")"), delimiterL1); | |
44 | logger.debug("level 1 tokens [delimiter = {}] [tokenCount = {}]", delimiterL1, tokensLevel1.size()); | |
45 | for (String tokenL1 : tokensLevel1) { | |
46 | logger.debug("L1 token => {} / {}", tokenL1, GeometryTokenizer.removeLeadingAndTrailingStrings(tokenL1, "(", ")")); | |
47 | List<String> tokensLevel2 = GeometryTokenizer.tokenize(GeometryTokenizer.removeLeadingAndTrailingStrings(tokenL1, "(", ")"), delimiterL2); | |
48 | logger.debug("level 2 tokens [delimiter = {}] [tokenCount = {}]", delimiterL2, tokensLevel2.size()); | |
49 | for (String tokenL2 : tokensLevel2) { | |
50 | logger.debug("L2 token => {} / {}", tokenL2, GeometryTokenizer.removeLeadingAndTrailingStrings(tokenL2, "(", ")")); | |
51 | } | |
52 | } | |
53 | } | |
54 | ||
55 | }⏎ |
0 | <configuration debug="false"> | |
1 | ||
2 | <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | |
3 | <layout class="ch.qos.logback.classic.PatternLayout"> | |
4 | <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> | |
5 | </layout> | |
6 | </appender> | |
7 | ||
8 | <root level="debug"> | |
9 | <appender-ref ref="STDOUT" /> | |
10 | </root> | |
11 | ||
12 | <logger name="com.github.dockerjava" level="ERROR"/> | |
13 | <logger name="org.testcontainers" level="ERROR"/> | |
14 | <logger name="net.postgis" level="ERROR"/> | |
15 | ||
16 | <logger name="org.postgis" level="ERROR"/> | |
17 | ||
18 | </configuration>⏎ |
0 | <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> | |
1 | <suite name="Postgis Geometry Test Suite" verbose="1"> | |
2 | ||
3 | <test name="Postgis Geometry Tests"> | |
4 | <classes> | |
5 | <class name="org.postgis.DatatypesTest"/> | |
6 | <class name="org.postgis.TokenizerTest"/> | |
7 | </classes> | |
8 | </test> | |
9 | ||
10 | </suite>⏎ |
0 | ||
1 | GNU LESSER GENERAL PUBLIC LICENSE | |
2 | Version 2.1, February 1999 | |
3 | ||
4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. | |
5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
6 | Everyone is permitted to copy and distribute verbatim copies | |
7 | of this license document, but changing it is not allowed. | |
8 | ||
9 | [This is the first released version of the Lesser GPL. It also counts | |
10 | as the successor of the GNU Library Public License, version 2, hence | |
11 | the version number 2.1.] | |
12 | ||
13 | Preamble | |
14 | ||
15 | The licenses for most software are designed to take away your | |
16 | freedom to share and change it. By contrast, the GNU General Public | |
17 | Licenses are intended to guarantee your freedom to share and change | |
18 | free software--to make sure the software is free for all its users. | |
19 | ||
20 | This license, the Lesser General Public License, applies to some | |
21 | specially designated software packages--typically libraries--of the | |
22 | Free Software Foundation and other authors who decide to use it. You | |
23 | can use it too, but we suggest you first think carefully about whether | |
24 | this license or the ordinary General Public License is the better | |
25 | strategy to use in any particular case, based on the explanations | |
26 | below. | |
27 | ||
28 | When we speak of free software, we are referring to freedom of use, | |
29 | not price. Our General Public Licenses are designed to make sure that | |
30 | you have the freedom to distribute copies of free software (and charge | |
31 | for this service if you wish); that you receive source code or can get | |
32 | it if you want it; that you can change the software and use pieces of | |
33 | it in new free programs; and that you are informed that you can do | |
34 | these things. | |
35 | ||
36 | To protect your rights, we need to make restrictions that forbid | |
37 | distributors to deny you these rights or to ask you to surrender these | |
38 | rights. These restrictions translate to certain responsibilities for | |
39 | you if you distribute copies of the library or if you modify it. | |
40 | ||
41 | For example, if you distribute copies of the library, whether gratis | |
42 | or for a fee, you must give the recipients all the rights that we gave | |
43 | you. You must make sure that they, too, receive or can get the source | |
44 | code. If you link other code with the library, you must provide | |
45 | complete object files to the recipients, so that they can relink them | |
46 | with the library after making changes to the library and recompiling | |
47 | it. And you must show them these terms so they know their rights. | |
48 | ||
49 | We protect your rights with a two-step method: (1) we copyright the | |
50 | library, and (2) we offer you this license, which gives you legal | |
51 | permission to copy, distribute and/or modify the library. | |
52 | ||
53 | To protect each distributor, we want to make it very clear that | |
54 | there is no warranty for the free library. Also, if the library is | |
55 | modified by someone else and passed on, the recipients should know | |
56 | that what they have is not the original version, so that the original | |
57 | author's reputation will not be affected by problems that might be | |
58 | introduced by others. | |
59 | ||
60 | Finally, software patents pose a constant threat to the existence of | |
61 | any free program. We wish to make sure that a company cannot | |
62 | effectively restrict the users of a free program by obtaining a | |
63 | restrictive license from a patent holder. Therefore, we insist that | |
64 | any patent license obtained for a version of the library must be | |
65 | consistent with the full freedom of use specified in this license. | |
66 | ||
67 | Most GNU software, including some libraries, is covered by the | |
68 | ordinary GNU General Public License. This license, the GNU Lesser | |
69 | General Public License, applies to certain designated libraries, and | |
70 | is quite different from the ordinary General Public License. We use | |
71 | this license for certain libraries in order to permit linking those | |
72 | libraries into non-free programs. | |
73 | ||
74 | When a program is linked with a library, whether statically or using | |
75 | a shared library, the combination of the two is legally speaking a | |
76 | combined work, a derivative of the original library. The ordinary | |
77 | General Public License therefore permits such linking only if the | |
78 | entire combination fits its criteria of freedom. The Lesser General | |
79 | Public License permits more lax criteria for linking other code with | |
80 | the library. | |
81 | ||
82 | We call this license the "Lesser" General Public License because it | |
83 | does Less to protect the user's freedom than the ordinary General | |
84 | Public License. It also provides other free software developers Less | |
85 | of an advantage over competing non-free programs. These disadvantages | |
86 | are the reason we use the ordinary General Public License for many | |
87 | libraries. However, the Lesser license provides advantages in certain | |
88 | special circumstances. | |
89 | ||
90 | For example, on rare occasions, there may be a special need to | |
91 | encourage the widest possible use of a certain library, so that it | |
92 | becomes a de-facto standard. To achieve this, non-free programs must | |
93 | be allowed to use the library. A more frequent case is that a free | |
94 | library does the same job as widely used non-free libraries. In this | |
95 | case, there is little to gain by limiting the free library to free | |
96 | software only, so we use the Lesser General Public License. | |
97 | ||
98 | In other cases, permission to use a particular library in non-free | |
99 | programs enables a greater number of people to use a large body of | |
100 | free software. For example, permission to use the GNU C Library in | |
101 | non-free programs enables many more people to use the whole GNU | |
102 | operating system, as well as its variant, the GNU/Linux operating | |
103 | system. | |
104 | ||
105 | Although the Lesser General Public License is Less protective of the | |
106 | users' freedom, it does ensure that the user of a program that is | |
107 | linked with the Library has the freedom and the wherewithal to run | |
108 | that program using a modified version of the Library. | |
109 | ||
110 | The precise terms and conditions for copying, distribution and | |
111 | modification follow. Pay close attention to the difference between a | |
112 | "work based on the library" and a "work that uses the library". The | |
113 | former contains code derived from the library, whereas the latter must | |
114 | be combined with the library in order to run. | |
115 | ||
116 | GNU LESSER GENERAL PUBLIC LICENSE | |
117 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |
118 | ||
119 | 0. This License Agreement applies to any software library or other | |
120 | program which contains a notice placed by the copyright holder or | |
121 | other authorized party saying it may be distributed under the terms of | |
122 | this Lesser General Public License (also called "this License"). | |
123 | Each licensee is addressed as "you". | |
124 | ||
125 | A "library" means a collection of software functions and/or data | |
126 | prepared so as to be conveniently linked with application programs | |
127 | (which use some of those functions and data) to form executables. | |
128 | ||
129 | The "Library", below, refers to any such software library or work | |
130 | which has been distributed under these terms. A "work based on the | |
131 | Library" means either the Library or any derivative work under | |
132 | copyright law: that is to say, a work containing the Library or a | |
133 | portion of it, either verbatim or with modifications and/or translated | |
134 | straightforwardly into another language. (Hereinafter, translation is | |
135 | included without limitation in the term "modification".) | |
136 | ||
137 | "Source code" for a work means the preferred form of the work for | |
138 | making modifications to it. For a library, complete source code means | |
139 | all the source code for all modules it contains, plus any associated | |
140 | interface definition files, plus the scripts used to control | |
141 | compilation and installation of the library. | |
142 | ||
143 | Activities other than copying, distribution and modification are not | |
144 | covered by this License; they are outside its scope. The act of | |
145 | running a program using the Library is not restricted, and output from | |
146 | such a program is covered only if its contents constitute a work based | |
147 | on the Library (independent of the use of the Library in a tool for | |
148 | writing it). Whether that is true depends on what the Library does | |
149 | and what the program that uses the Library does. | |
150 | ||
151 | 1. You may copy and distribute verbatim copies of the Library's | |
152 | complete source code as you receive it, in any medium, provided that | |
153 | you conspicuously and appropriately publish on each copy an | |
154 | appropriate copyright notice and disclaimer of warranty; keep intact | |
155 | all the notices that refer to this License and to the absence of any | |
156 | warranty; and distribute a copy of this License along with the | |
157 | Library. | |
158 | ||
159 | You may charge a fee for the physical act of transferring a copy, | |
160 | and you may at your option offer warranty protection in exchange for a | |
161 | fee. | |
162 | ||
163 | 2. You may modify your copy or copies of the Library or any portion | |
164 | of it, thus forming a work based on the Library, and copy and | |
165 | distribute such modifications or work under the terms of Section 1 | |
166 | above, provided that you also meet all of these conditions: | |
167 | ||
168 | a) The modified work must itself be a software library. | |
169 | ||
170 | b) You must cause the files modified to carry prominent notices | |
171 | stating that you changed the files and the date of any change. | |
172 | ||
173 | c) You must cause the whole of the work to be licensed at no | |
174 | charge to all third parties under the terms of this License. | |
175 | ||
176 | d) If a facility in the modified Library refers to a function or a | |
177 | table of data to be supplied by an application program that uses | |
178 | the facility, other than as an argument passed when the facility | |
179 | is invoked, then you must make a good faith effort to ensure that, | |
180 | in the event an application does not supply such function or | |
181 | table, the facility still operates, and performs whatever part of | |
182 | its purpose remains meaningful. | |
183 | ||
184 | (For example, a function in a library to compute square roots has | |
185 | a purpose that is entirely well-defined independent of the | |
186 | application. Therefore, Subsection 2d requires that any | |
187 | application-supplied function or table used by this function must | |
188 | be optional: if the application does not supply it, the square | |
189 | root function must still compute square roots.) | |
190 | ||
191 | These requirements apply to the modified work as a whole. If | |
192 | identifiable sections of that work are not derived from the Library, | |
193 | and can be reasonably considered independent and separate works in | |
194 | themselves, then this License, and its terms, do not apply to those | |
195 | sections when you distribute them as separate works. But when you | |
196 | distribute the same sections as part of a whole which is a work based | |
197 | on the Library, the distribution of the whole must be on the terms of | |
198 | this License, whose permissions for other licensees extend to the | |
199 | entire whole, and thus to each and every part regardless of who wrote | |
200 | it. | |
201 | ||
202 | Thus, it is not the intent of this section to claim rights or contest | |
203 | your rights to work written entirely by you; rather, the intent is to | |
204 | exercise the right to control the distribution of derivative or | |
205 | collective works based on the Library. | |
206 | ||
207 | In addition, mere aggregation of another work not based on the Library | |
208 | with the Library (or with a work based on the Library) on a volume of | |
209 | a storage or distribution medium does not bring the other work under | |
210 | the scope of this License. | |
211 | ||
212 | 3. You may opt to apply the terms of the ordinary GNU General Public | |
213 | License instead of this License to a given copy of the Library. To do | |
214 | this, you must alter all the notices that refer to this License, so | |
215 | that they refer to the ordinary GNU General Public License, version 2, | |
216 | instead of to this License. (If a newer version than version 2 of the | |
217 | ordinary GNU General Public License has appeared, then you can specify | |
218 | that version instead if you wish.) Do not make any other change in | |
219 | these notices. | |
220 | ||
221 | Once this change is made in a given copy, it is irreversible for | |
222 | that copy, so the ordinary GNU General Public License applies to all | |
223 | subsequent copies and derivative works made from that copy. | |
224 | ||
225 | This option is useful when you wish to copy part of the code of | |
226 | the Library into a program that is not a library. | |
227 | ||
228 | 4. You may copy and distribute the Library (or a portion or | |
229 | derivative of it, under Section 2) in object code or executable form | |
230 | under the terms of Sections 1 and 2 above provided that you accompany | |
231 | it with the complete corresponding machine-readable source code, which | |
232 | must be distributed under the terms of Sections 1 and 2 above on a | |
233 | medium customarily used for software interchange. | |
234 | ||
235 | If distribution of object code is made by offering access to copy | |
236 | from a designated place, then offering equivalent access to copy the | |
237 | source code from the same place satisfies the requirement to | |
238 | distribute the source code, even though third parties are not | |
239 | compelled to copy the source along with the object code. | |
240 | ||
241 | 5. A program that contains no derivative of any portion of the | |
242 | Library, but is designed to work with the Library by being compiled or | |
243 | linked with it, is called a "work that uses the Library". Such a | |
244 | work, in isolation, is not a derivative work of the Library, and | |
245 | therefore falls outside the scope of this License. | |
246 | ||
247 | However, linking a "work that uses the Library" with the Library | |
248 | creates an executable that is a derivative of the Library (because it | |
249 | contains portions of the Library), rather than a "work that uses the | |
250 | library". The executable is therefore covered by this License. | |
251 | Section 6 states terms for distribution of such executables. | |
252 | ||
253 | When a "work that uses the Library" uses material from a header file | |
254 | that is part of the Library, the object code for the work may be a | |
255 | derivative work of the Library even though the source code is not. | |
256 | Whether this is true is especially significant if the work can be | |
257 | linked without the Library, or if the work is itself a library. The | |
258 | threshold for this to be true is not precisely defined by law. | |
259 | ||
260 | If such an object file uses only numerical parameters, data | |
261 | structure layouts and accessors, and small macros and small inline | |
262 | functions (ten lines or less in length), then the use of the object | |
263 | file is unrestricted, regardless of whether it is legally a derivative | |
264 | work. (Executables containing this object code plus portions of the | |
265 | Library will still fall under Section 6.) | |
266 | ||
267 | Otherwise, if the work is a derivative of the Library, you may | |
268 | distribute the object code for the work under the terms of Section 6. | |
269 | Any executables containing that work also fall under Section 6, | |
270 | whether or not they are linked directly with the Library itself. | |
271 | ||
272 | 6. As an exception to the Sections above, you may also combine or | |
273 | link a "work that uses the Library" with the Library to produce a | |
274 | work containing portions of the Library, and distribute that work | |
275 | under terms of your choice, provided that the terms permit | |
276 | modification of the work for the customer's own use and reverse | |
277 | engineering for debugging such modifications. | |
278 | ||
279 | You must give prominent notice with each copy of the work that the | |
280 | Library is used in it and that the Library and its use are covered by | |
281 | this License. You must supply a copy of this License. If the work | |
282 | during execution displays copyright notices, you must include the | |
283 | copyright notice for the Library among them, as well as a reference | |
284 | directing the user to the copy of this License. Also, you must do one | |
285 | of these things: | |
286 | ||
287 | a) Accompany the work with the complete corresponding | |
288 | machine-readable source code for the Library including whatever | |
289 | changes were used in the work (which must be distributed under | |
290 | Sections 1 and 2 above); and, if the work is an executable linked | |
291 | with the Library, with the complete machine-readable "work that | |
292 | uses the Library", as object code and/or source code, so that the | |
293 | user can modify the Library and then relink to produce a modified | |
294 | executable containing the modified Library. (It is understood | |
295 | that the user who changes the contents of definitions files in the | |
296 | Library will not necessarily be able to recompile the application | |
297 | to use the modified definitions.) | |
298 | ||
299 | b) Use a suitable shared library mechanism for linking with the | |
300 | Library. A suitable mechanism is one that (1) uses at run time a | |
301 | copy of the library already present on the user's computer system, | |
302 | rather than copying library functions into the executable, and (2) | |
303 | will operate properly with a modified version of the library, if | |
304 | the user installs one, as long as the modified version is | |
305 | interface-compatible with the version that the work was made with. | |
306 | ||
307 | c) Accompany the work with a written offer, valid for at least | |
308 | three years, to give the same user the materials specified in | |
309 | Subsection 6a, above, for a charge no more than the cost of | |
310 | performing this distribution. | |
311 | ||
312 | d) If distribution of the work is made by offering access to copy | |
313 | from a designated place, offer equivalent access to copy the above | |
314 | specified materials from the same place. | |
315 | ||
316 | e) Verify that the user has already received a copy of these | |
317 | materials or that you have already sent this user a copy. | |
318 | ||
319 | For an executable, the required form of the "work that uses the | |
320 | Library" must include any data and utility programs needed for | |
321 | reproducing the executable from it. However, as a special exception, | |
322 | the materials to be distributed need not include anything that is | |
323 | normally distributed (in either source or binary form) with the major | |
324 | components (compiler, kernel, and so on) of the operating system on | |
325 | which the executable runs, unless that component itself accompanies | |
326 | the executable. | |
327 | ||
328 | It may happen that this requirement contradicts the license | |
329 | restrictions of other proprietary libraries that do not normally | |
330 | accompany the operating system. Such a contradiction means you cannot | |
331 | use both them and the Library together in an executable that you | |
332 | distribute. | |
333 | ||
334 | 7. You may place library facilities that are a work based on the | |
335 | Library side-by-side in a single library together with other library | |
336 | facilities not covered by this License, and distribute such a combined | |
337 | library, provided that the separate distribution of the work based on | |
338 | the Library and of the other library facilities is otherwise | |
339 | permitted, and provided that you do these two things: | |
340 | ||
341 | a) Accompany the combined library with a copy of the same work | |
342 | based on the Library, uncombined with any other library | |
343 | facilities. This must be distributed under the terms of the | |
344 | Sections above. | |
345 | ||
346 | b) Give prominent notice with the combined library of the fact | |
347 | that part of it is a work based on the Library, and explaining | |
348 | where to find the accompanying uncombined form of the same work. | |
349 | ||
350 | 8. You may not copy, modify, sublicense, link with, or distribute | |
351 | the Library except as expressly provided under this License. Any | |
352 | attempt otherwise to copy, modify, sublicense, link with, or | |
353 | distribute the Library is void, and will automatically terminate your | |
354 | rights under this License. However, parties who have received copies, | |
355 | or rights, from you under this License will not have their licenses | |
356 | terminated so long as such parties remain in full compliance. | |
357 | ||
358 | 9. You are not required to accept this License, since you have not | |
359 | signed it. However, nothing else grants you permission to modify or | |
360 | distribute the Library or its derivative works. These actions are | |
361 | prohibited by law if you do not accept this License. Therefore, by | |
362 | modifying or distributing the Library (or any work based on the | |
363 | Library), you indicate your acceptance of this License to do so, and | |
364 | all its terms and conditions for copying, distributing or modifying | |
365 | the Library or works based on it. | |
366 | ||
367 | 10. Each time you redistribute the Library (or any work based on the | |
368 | Library), the recipient automatically receives a license from the | |
369 | original licensor to copy, distribute, link with or modify the Library | |
370 | subject to these terms and conditions. You may not impose any further | |
371 | restrictions on the recipients' exercise of the rights granted herein. | |
372 | You are not responsible for enforcing compliance by third parties with | |
373 | this License. | |
374 | ||
375 | 11. If, as a consequence of a court judgment or allegation of patent | |
376 | infringement or for any other reason (not limited to patent issues), | |
377 | conditions are imposed on you (whether by court order, agreement or | |
378 | otherwise) that contradict the conditions of this License, they do not | |
379 | excuse you from the conditions of this License. If you cannot | |
380 | distribute so as to satisfy simultaneously your obligations under this | |
381 | License and any other pertinent obligations, then as a consequence you | |
382 | may not distribute the Library at all. For example, if a patent | |
383 | license would not permit royalty-free redistribution of the Library by | |
384 | all those who receive copies directly or indirectly through you, then | |
385 | the only way you could satisfy both it and this License would be to | |
386 | refrain entirely from distribution of the Library. | |
387 | ||
388 | If any portion of this section is held invalid or unenforceable under | |
389 | any particular circumstance, the balance of the section is intended to | |
390 | apply, and the section as a whole is intended to apply in other | |
391 | circumstances. | |
392 | ||
393 | It is not the purpose of this section to induce you to infringe any | |
394 | patents or other property right claims or to contest validity of any | |
395 | such claims; this section has the sole purpose of protecting the | |
396 | integrity of the free software distribution system which is | |
397 | implemented by public license practices. Many people have made | |
398 | generous contributions to the wide range of software distributed | |
399 | through that system in reliance on consistent application of that | |
400 | system; it is up to the author/donor to decide if he or she is willing | |
401 | to distribute software through any other system and a licensee cannot | |
402 | impose that choice. | |
403 | ||
404 | This section is intended to make thoroughly clear what is believed to | |
405 | be a consequence of the rest of this License. | |
406 | ||
407 | 12. If the distribution and/or use of the Library is restricted in | |
408 | certain countries either by patents or by copyrighted interfaces, the | |
409 | original copyright holder who places the Library under this License | |
410 | may add an explicit geographical distribution limitation excluding those | |
411 | countries, so that distribution is permitted only in or among | |
412 | countries not thus excluded. In such case, this License incorporates | |
413 | the limitation as if written in the body of this License. | |
414 | ||
415 | 13. The Free Software Foundation may publish revised and/or new | |
416 | versions of the Lesser General Public License from time to time. | |
417 | Such new versions will be similar in spirit to the present version, | |
418 | but may differ in detail to address new problems or concerns. | |
419 | ||
420 | Each version is given a distinguishing version number. If the Library | |
421 | specifies a version number of this License which applies to it and | |
422 | "any later version", you have the option of following the terms and | |
423 | conditions either of that version or of any later version published by | |
424 | the Free Software Foundation. If the Library does not specify a | |
425 | license version number, you may choose any version ever published by | |
426 | the Free Software Foundation. | |
427 | ||
428 | 14. If you wish to incorporate parts of the Library into other free | |
429 | programs whose distribution conditions are incompatible with these, | |
430 | write to the author to ask for permission. For software which is | |
431 | copyrighted by the Free Software Foundation, write to the Free | |
432 | Software Foundation; we sometimes make exceptions for this. Our | |
433 | decision will be guided by the two goals of preserving the free status | |
434 | of all derivatives of our free software and of promoting the sharing | |
435 | and reuse of software generally. | |
436 | ||
437 | NO WARRANTY | |
438 | ||
439 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO | |
440 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. | |
441 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR | |
442 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY | |
443 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE | |
444 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
445 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE | |
446 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME | |
447 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | |
448 | ||
449 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN | |
450 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY | |
451 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU | |
452 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR | |
453 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE | |
454 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING | |
455 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A | |
456 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF | |
457 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH | |
458 | DAMAGES. | |
459 | ||
460 | END OF TERMS AND CONDITIONS | |
461 | ||
462 | How to Apply These Terms to Your New Libraries | |
463 | ||
464 | If you develop a new library, and you want it to be of the greatest | |
465 | possible use to the public, we recommend making it free software that | |
466 | everyone can redistribute and change. You can do so by permitting | |
467 | redistribution under these terms (or, alternatively, under the terms | |
468 | of the ordinary General Public License). | |
469 | ||
470 | To apply these terms, attach the following notices to the library. | |
471 | It is safest to attach them to the start of each source file to most | |
472 | effectively convey the exclusion of warranty; and each file should | |
473 | have at least the "copyright" line and a pointer to where the full | |
474 | notice is found. | |
475 | ||
476 | ||
477 | <one line to give the library's name and a brief idea of what it does.> | |
478 | Copyright (C) <year> <name of author> | |
479 | ||
480 | This library is free software; you can redistribute it and/or | |
481 | modify it under the terms of the GNU Lesser General Public | |
482 | License as published by the Free Software Foundation; either | |
483 | version 2.1 of the License, or (at your option) any later version. | |
484 | ||
485 | This library is distributed in the hope that it will be useful, | |
486 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
487 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
488 | Lesser General Public License for more details. | |
489 | ||
490 | You should have received a copy of the GNU Lesser General Public | |
491 | License along with this library; if not, write to the Free Software | |
492 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
493 | ||
494 | Also add information on how to contact you by electronic and paper mail. | |
495 | ||
496 | You should also get your employer (if you work as a programmer) or | |
497 | your school, if any, to sign a "copyright disclaimer" for the library, | |
498 | if necessary. Here is a sample; alter the names: | |
499 | ||
500 | Yoyodyne, Inc., hereby disclaims all copyright interest in the | |
501 | library `Frob' (a library for tweaking knobs) written by James | |
502 | Random Hacker. | |
503 | ||
504 | <signature of Ty Coon>, 1 April 1990 | |
505 | Ty Coon, President of Vice | |
506 | ||
507 | That's all there is to it! | |
508 | ||
509 |
0 | ||
1 | *** PostGIS JDBC Driver extension README / FAQ *** | |
2 | ||
3 | (C) 2005 Markus Schaber <markus.schaber@logix-tt.com> | |
4 | ||
5 | ||
6 | * What is it all about? * | |
7 | ||
8 | JDBC is an database driver specification for Java. Like ODBC in the C | |
9 | world, JDBC allows java applications to transparently use different | |
10 | JDBC compliant databases without any source code changes. PostgreSQL, | |
11 | the database PostGIS is written for, comes with a driver that | |
12 | follows this specification. For downloads and more info, see: | |
13 | http://jdbc.postgresql.org/download.html | |
14 | ||
15 | The purpose of the JDBC Driver extension is to give the PostgreSQL | |
16 | JDBC driver some understanding of the PostGIS data types (Geometry, | |
17 | Box3D, Box2D). Without this, the Application can only get byte arrays | |
18 | or strings (binary and text representation, rsp.) and has to parse it | |
19 | on its own. When registering this extension, the Application can | |
20 | simply call getObject(column) on the result of the query, and get a | |
21 | real java object that is modeled after the OpenGIS spec. It also can | |
22 | create or modify this objects itsself and then pass them into the | |
23 | database via the PreparedStatement.setObject() method. | |
24 | ||
25 | Currently, the code is tested with PostGIS 0.8.1, 0.9.1. 0.9.2 and | |
26 | 1.0.0. It supports both the new hex-encoded EWKB canonical text | |
27 | representation used by PostGIS 1.0.0 lwgeom code, and the old, less | |
28 | efficient WKT like representation used by previous releases when | |
29 | reading data from the server. When sending data to the server, it | |
30 | currently always uses the latter form, which is compatible to all | |
31 | PostGIS versions. | |
32 | ||
33 | ||
34 | * Do I need it? * | |
35 | ||
36 | If you happen to write GIS applications, you can propably benefit. | |
37 | ||
38 | In case your applications are PostGIS specific, you can fully exploit | |
39 | the functionality, see "How to I use it" below for instructions and | |
40 | the src/examples directory for some code examples. | |
41 | ||
42 | If you rather prefer to stay OpenGIS compliant, then you cannot use | |
43 | the full driver embedding, as this is PostGIS specific functionality. | |
44 | But you can still use the geometry classes as a lightweight java | |
45 | geometry model if you do not want to use a full-blown GIS | |
46 | implementation like jts. Simply use the asText() and | |
47 | GeometryFromText() OpenGIS SQL functions against whichever OpenGIS | |
48 | compliant server you want, and use the WKT parsing constructors or | |
49 | PGgeometry.geomFromString() as well as Geometry.toString() to convert | |
50 | between WKT strings and geometry objects. | |
51 | ||
52 | ||
53 | * Is it free? * | |
54 | ||
55 | Yes. The actual Driver extension code is licensed under the GNU LGPL, | |
56 | this allows everyone to include the code in his projects. You do not | |
57 | have to pay any license fees, and you can keep your own application | |
58 | code proprietary, but you have to make the PostGIS source code available | |
59 | to any receivers, including any modifications you apply to it. For | |
60 | details, please see the license file COPYING_LGPL. | |
61 | ||
62 | The Build files and examples are licensed under GNU GPL, just like the | |
63 | rest of PostGIS is. This is not LGPL as applications usually do not | |
64 | link against those. | |
65 | ||
66 | ||
67 | * How do I build it? * | |
68 | ||
69 | There are older make files with which you can try to build, but maven is recommended, | |
70 | as it handles dependencies on a better and cleaner way. | |
71 | ||
72 | You have to install maven on your computer to build it. To install maven you can try | |
73 | to search on your software repositories or read the documentation: | |
74 | http://maven.apache.org/download.html | |
75 | ||
76 | To compile your postgis driver, go to the jdbc folder and execute the console | |
77 | command "mvn package". This should create a postgis jar on the target folder | |
78 | inside the jdbc folder. | |
79 | ||
80 | Note that your postgis driver version does not constrain the PostgreSQL | |
81 | server version. As the JDBC drivers are downwards compatible against older | |
82 | servers, and PostgreSQL servers typically accept older clients, you can | |
83 | easily use e. G. a pgjdbc 8.0 against a PostgreSQL 7.3 server. To benefit | |
84 | from optimizations and bugfixes, it is generally suggested to use the | |
85 | newest stable pgjdbc build that is documented to work against your | |
86 | server release. | |
87 | ||
88 | * It is called jdbc2 - does it work with jdbc3, too? * | |
89 | ||
90 | To make it short: The naming does not refer to SUN jdbc standard releases | |
91 | jdbc-1, jdbc-2 or jdbc-3. | |
92 | ||
93 | The current naming is somehow unfortunate. The directory simply is named | |
94 | jdbc2 because it is the successor of Paul Ramsey's original jdbc directory, | |
95 | which used to exist parallel in the CVS repository. As CVS does its best | |
96 | to hinder useful version tracking across file renames, the name was kept | |
97 | even after removal of the original jdbc subproject. | |
98 | ||
99 | Please note that the PostgreSQL JDBC driver itsself is released in | |
100 | several flavours for different JDBC relases and sun JDK releases, but | |
101 | currently, the same postgis.jar should work with all of them. If not, | |
102 | you clearly found a bug, and we kindly ask you to report it. | |
103 | ||
104 | If you run into troubles, make shure that you use the newest pgjdbc build. | |
105 | Especially pre releases are known to contain bugs (that's why they are pre | |
106 | releases), and e. G. 8.0 build 309 contained some problems that are fixed | |
107 | in 8.0 build 313. | |
108 | ||
109 | ||
110 | * How do I use it? * | |
111 | ||
112 | To use the PostGIS types, you need the postgis.jar and the pgjdbc | |
113 | driver in your classpath. | |
114 | ||
115 | The PostGIS extension must be registered within the JDBC driver. | |
116 | There are three ways to do this: | |
117 | ||
118 | - If you use pgjdbc 8.0, the org/postgresql/driverconfig.properties | |
119 | file contained in the postgis.jar autoregisters the PostGIS | |
120 | extension for the PostGIS data types (geometry, box2d, box3d) | |
121 | within the pgjdbc driver. | |
122 | ||
123 | - You can use the net.postgis.jdbc.DriverWrapper as replacement for the | |
124 | jdbc driver. This class wraps the PostGreSQL Driver to | |
125 | transparently add the PostGIS Object Classes. This method currently | |
126 | works both with J2EE DataSources, and with the older DriverManager | |
127 | framework. I's a thin wrapper around org.postgresql.Driver that | |
128 | simply registers the extension on every new connection created. | |
129 | ||
130 | To use it, you replace the "jdbc:postgresql:" with a | |
131 | "jdbc:postgresql_postGIS" in the jdbc URL, and make your | |
132 | environment aware of the new Driver class. | |
133 | ||
134 | DriverManager users simply register net/postgis/DriverWrapper | |
135 | instead of (or in addition to) org.postgresql.Driver, see | |
136 | examples/TestBoxes.connect() for an working code. | |
137 | ||
138 | DataSource users similarly have to configure their datasource to | |
139 | use the different class. The following works for jboss, put it in | |
140 | your-ds.xml: <driver-class>net.postgis.jdbc.DriverWrapper</driver-class> | |
141 | ||
142 | - Of course, you can also manually register the Datatypes on your | |
143 | pgjdbc connection. You have to cast your connection to PGConnection | |
144 | and then call: | |
145 | ||
146 | pgconn.addDataType("geometry", "net.postgis.jdbc.PGgeometry"); | |
147 | pgconn.addDataType("box3d", "net.postgis.jdbc.PGbox3d"); | |
148 | pgconn.addDataType("box2d", "net.postgis.jdbc.PGbox2d"); | |
149 | ||
150 | You may need to dig through some wrappers when running in an | |
151 | appserver. E. G. for JBoss, The datasource actually gives you a | |
152 | instance of org.jboss.resource.adapter.jdbc.WrappedConnection and | |
153 | have to call getUnderlyingConnection() on it to get the | |
154 | PGConnection instance.) | |
155 | ||
156 | Also note that the above addDataType() methods known from earlier | |
157 | pgjdbc versions are deprecated in pgjdbc 8.0 (but still work), see | |
158 | the commented code variants in the DriverWrapper.addGisTypes() | |
159 | method for an alternative. | |
160 | ||
161 | Note: Even using pgjdbc 8.0, you may still want to use the second or | |
162 | third approach if you have several pgjdbc extensions that | |
163 | autoregister for the same PostGIS types, as the driver cannot guess | |
164 | which extension it should actually use on which connection. The | |
165 | current pgjdbc implementation simply parses all | |
166 | org/postgresql/driverconfig.properties the classloader can find in his | |
167 | classpath, using the first definition found for each type. | |
168 | ||
169 | ||
170 | * How to I run the tests? Are they allowed to fail? * | |
171 | ||
172 | There are two types of tests provided, offline and online. Offline | |
173 | tests can run without a PostGIS server, the online tests need a | |
174 | PostGIS server to connect to. | |
175 | ||
176 | - Offline Tests | |
177 | ||
178 | The easiest way to run the offline tests is "make offlinetests". | |
179 | ||
180 | The offline tests should always complete without any failure. If | |
181 | you happen to get a failure here, it is a bug in the PostGIS code | |
182 | (or, very unlikely, in the JDK/JRE or Hardware you use). Please | |
183 | contact the PostGIS developer list in this case. | |
184 | ||
185 | - Online tests | |
186 | ||
187 | The online tests can be ran with "make onlinetests", but they need | |
188 | a specially prepared database to connect against, and the pgjdbc | |
189 | driver available in your classpath. The Makefile provides defaults | |
190 | for PGHOST, PGPOR, PGDATABASE, PGUSER and PGPASS, you can override | |
191 | them for your needs. For the jtest, the user needs to create and | |
192 | drop table privileges, the two other tests do not use any table. | |
193 | Make shure you have the PostGIS installed in the database. | |
194 | ||
195 | None of the online tests should report any failure. However, some of the | |
196 | tests are skipped against PostGix 0.X servers as 0.8.X and 0.9.X, those | |
197 | are the box2d tests (because this datatype simply is missing on those | |
198 | releases), as well as 22 skipped tests for some geometry representations | |
199 | that those old releases do not support. This is a PostGIS server side | |
200 | problem as the server fails to parse some OpenGIS compliant WKT | |
201 | representations, and structurally (but not geometrically or topologically) | |
202 | mangles some other geometries. They are unlikely to be fixed in those | |
203 | releases as users should migrate to PostGIS 1.0. | |
204 | ||
205 | The Autoregister Test needs a pgjdbc version 8.0 or newer, and will | |
206 | simply do nothing with older pgjdbc versions. | |
207 | ||
208 | If you get any failure messages in the online tests, check whether | |
209 | your really fulfil the prerequisites above. If yes, please contact | |
210 | the PostGIS developer list. | |
211 | ||
212 | ||
213 | * What about the JTS stuff * | |
214 | ||
215 | There's beta support for the JTS 1.6 geometry implementations instead of the | |
216 | native PostGIS classes on the java client side. Simply add jts_1.6.jar to your | |
217 | CLASSPATH, "make postgis_jts" and use at your own risk. | |
218 | ||
219 | ||
220 | * How can I contact you? * | |
221 | ||
222 | Well, the best place are the official PostGIS mailing lists for PostGIS, | |
223 | subscription information is linked at: | |
224 | ||
225 | http://postgis.net/ | |
226 | ||
227 | If you want to report errors, please try to send us all the details we need | |
228 | to reproduce your problem. A small, self-contained test case would be best. | |
229 | ||
230 | ||
231 | * Phew. That's all? * | |
232 | ||
233 | Yes. For now, at least. | |
234 | ||
235 | Happy Coding! |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
2 | <modelVersion>4.0.0</modelVersion> | |
3 | ||
4 | <parent> | |
5 | <groupId>net.postgis</groupId> | |
6 | <artifactId>postgis-java-aggregator</artifactId> | |
7 | <version>2021.1.0</version> | |
8 | </parent> | |
9 | ||
10 | <artifactId>postgis-jdbc</artifactId> | |
11 | <version>2021.1.0</version> | |
12 | <packaging>jar</packaging> | |
13 | ||
14 | <name>Postgis JDBC Driver</name> | |
15 | <description>PostGIS adds support for geographic objects to the PostgreSQL object-relational database.</description> | |
16 | ||
17 | <properties /> | |
18 | ||
19 | <dependencies> | |
20 | <dependency> | |
21 | <groupId>net.postgis</groupId> | |
22 | <artifactId>postgis-geometry</artifactId> | |
23 | <version>2021.1.0</version> | |
24 | </dependency> | |
25 | <dependency> | |
26 | <groupId>org.postgresql</groupId> | |
27 | <artifactId>postgresql</artifactId> | |
28 | <version>${dependency.postgresql-jdbc.version}</version> | |
29 | </dependency> | |
30 | <dependency> | |
31 | <groupId>net.postgis.tools</groupId> | |
32 | <artifactId>test-utils</artifactId> | |
33 | <version>2021.1.0</version> | |
34 | <scope>test</scope> | |
35 | </dependency> | |
36 | </dependencies> | |
37 | ||
38 | <build> | |
39 | <plugins> | |
40 | <plugin> | |
41 | <artifactId>maven-jar-plugin</artifactId> | |
42 | <configuration> | |
43 | <archive> | |
44 | <manifestEntries> | |
45 | <Automatic-Module-Name>net.postgis.jdbc</Automatic-Module-Name> | |
46 | </manifestEntries> | |
47 | </archive> | |
48 | </configuration> | |
49 | </plugin> | |
50 | <plugin> | |
51 | <groupId>org.apache.maven.plugins</groupId> | |
52 | <artifactId>maven-failsafe-plugin</artifactId> | |
53 | </plugin> | |
54 | </plugins> | |
55 | </build> | |
56 | ||
57 | </project> |
0 | module net.postgis.jdbc { | |
1 | requires java.sql; | |
2 | ||
3 | requires org.postgresql.jdbc; | |
4 | ||
5 | requires net.postgis.geometry; | |
6 | ||
7 | exports net.postgis.jdbc; | |
8 | }⏎ |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
16 | * | |
17 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
18 | */ | |
19 | ||
20 | package net.postgis.jdbc; | |
21 | ||
22 | ||
23 | import java.sql.Connection; | |
24 | import java.sql.SQLException; | |
25 | import java.util.Properties; | |
26 | import java.util.logging.Level; | |
27 | import java.util.logging.Logger; | |
28 | ||
29 | import org.postgresql.Driver; | |
30 | import org.postgresql.PGConnection; | |
31 | ||
32 | ||
33 | /** | |
34 | * DriverWrapper | |
35 | * | |
36 | * Wraps the PostGreSQL Driver to transparently add the PostGIS Object Classes. | |
37 | * This avoids the need of explicit addDataType() calls from the driver users | |
38 | * side. | |
39 | * | |
40 | * This method currently works with J2EE DataSource implementations, and with | |
41 | * DriverManager framework. | |
42 | * | |
43 | * Simply replace the "jdbc:postgresql:" with a "jdbc:postgresql_postGIS:" in | |
44 | * the jdbc URL. | |
45 | * | |
46 | * When using the drivermanager, you need to initialize DriverWrapper instead of | |
47 | * (or in addition to) org.postgresql.Driver. When using a J2EE DataSource | |
48 | * implementation, set the driver class property in the datasource config, the | |
49 | * following works for jboss: | |
50 | * | |
51 | * <code> | |
52 | * <driver-class>net.postgis.jdbc.DriverWrapper</driver-class> | |
53 | * </code> | |
54 | * If you don't like or want to use the DriverWrapper, you have two | |
55 | * alternatives, see the README file. | |
56 | * | |
57 | * Also note that the addDataType() methods known from earlier pgjdbc versions | |
58 | * are deprecated in pgjdbc 8.0, see the commented code variants in the | |
59 | * addGisTypes() method. | |
60 | * | |
61 | * This wrapper always uses EWKT as canonical text representation, and thus | |
62 | * works against PostGIS 1.x servers as well as 0.x (tested with 0.8, 0.9 and | |
63 | * 1.0). | |
64 | * | |
65 | * @author {@literal Markus Schaber <markus.schaber@logix-tt.com>} | |
66 | * @see DriverWrapperLW | |
67 | * @see DriverWrapperAutoprobe | |
68 | */ | |
69 | public class DriverWrapper extends Driver { | |
70 | ||
71 | /** The static logger instance. */ | |
72 | protected static final Logger logger = Logger.getLogger("net.postgis.jdbc.DriverWrapper"); | |
73 | ||
74 | public static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; | |
75 | public static final String POSTGIS_PROTOCOL = "jdbc:postgresql_postGIS:"; | |
76 | public static final String REVISION = "$Revision$"; | |
77 | protected static TypesAdder ta72 = null; | |
78 | protected static TypesAdder ta74 = null; | |
79 | protected static TypesAdder ta80 = null; | |
80 | ||
81 | protected TypesAdder typesAdder; | |
82 | ||
83 | ||
84 | static { | |
85 | try { | |
86 | // Try to register ourself to the DriverManager | |
87 | java.sql.DriverManager.registerDriver(new DriverWrapper()); | |
88 | } catch (SQLException e) { | |
89 | logger.log(Level.WARNING, "Error registering PostGIS Wrapper Driver", e); | |
90 | } | |
91 | } | |
92 | ||
93 | ||
94 | /** | |
95 | * Default constructor. | |
96 | * | |
97 | * This also loads the appropriate TypesAdder for our SQL Driver instance. | |
98 | * | |
99 | * @throws SQLException when a SQLException occurs | |
100 | */ | |
101 | public DriverWrapper() throws SQLException { | |
102 | super(); | |
103 | typesAdder = getTypesAdder(this); | |
104 | // The debug method is @since 7.2 | |
105 | if (super.getMajorVersion() > 8 || super.getMinorVersion() > 1) { | |
106 | logger.fine(this.getClass().getName() + " loaded TypesAdder: " | |
107 | + typesAdder.getClass().getName()); | |
108 | } | |
109 | } | |
110 | ||
111 | ||
112 | protected static TypesAdder getTypesAdder(final Driver d) throws SQLException { | |
113 | if (d.getMajorVersion() == 7) { | |
114 | if (d.getMinorVersion() >= 3) { | |
115 | if (ta74 == null) { | |
116 | ta74 = loadTypesAdder("74"); | |
117 | } | |
118 | return ta74; | |
119 | } else { | |
120 | if (ta72 == null) { | |
121 | ta72 = loadTypesAdder("72"); | |
122 | } | |
123 | return ta72; | |
124 | } | |
125 | } else { | |
126 | if (ta80 == null) { | |
127 | ta80 = loadTypesAdder("80"); | |
128 | } | |
129 | return ta80; | |
130 | } | |
131 | } | |
132 | ||
133 | ||
134 | private static TypesAdder loadTypesAdder(final String version) throws SQLException { | |
135 | try { | |
136 | Class klass = Class.forName("net.postgis.jdbc.DriverWrapper$TypesAdder" + version); | |
137 | return (TypesAdder) klass.newInstance(); | |
138 | } catch (Exception e) { | |
139 | throw new SQLException("Cannot create TypesAdder instance! " + e.getMessage()); | |
140 | } | |
141 | } | |
142 | ||
143 | ||
144 | /** | |
145 | * Creates a postgresql connection, and then adds the PostGIS data types to it calling addpgtypes(). | |
146 | * | |
147 | * A side-effect of this method is that the specified url parameter may be be changed | |
148 | * | |
149 | * @param url the URL of the database to connect to (may be changed as a side-effect of this method) | |
150 | * @param info a list of arbitrary tag/value pairs as connection arguments | |
151 | * @return a connection to the URL or null if it isnt us | |
152 | * @exception SQLException if a database access error occurs | |
153 | * | |
154 | * @see java.sql.Driver#connect | |
155 | * @see org.postgresql.Driver | |
156 | */ | |
157 | public java.sql.Connection connect(String url, final Properties info) throws SQLException { | |
158 | url = mangleURL(url); | |
159 | Connection result = super.connect(url, info); | |
160 | typesAdder.addGT(result, useLW(result)); | |
161 | return result; | |
162 | } | |
163 | ||
164 | ||
165 | /** | |
166 | * Do we have HexWKB as well known text representation - to be overridden by | |
167 | * subclasses. | |
168 | * | |
169 | * @param result Connection to check | |
170 | * @return true if using EWKB, false otherwise | |
171 | */ | |
172 | protected boolean useLW(final Connection result) { | |
173 | if (result == null) { | |
174 | throw new IllegalArgumentException("null is no valid parameter"); | |
175 | } | |
176 | return false; | |
177 | } | |
178 | ||
179 | ||
180 | /** | |
181 | * Check whether the driver thinks he can handle the given URL. | |
182 | * | |
183 | * A side-effect of this method is that the specified url parameter may be be changed | |
184 | * | |
185 | * @see java.sql.Driver#acceptsURL | |
186 | * @param url the URL of the driver (may be changed as a side-effect of this method) | |
187 | * @return true if this driver accepts the given URL | |
188 | */ | |
189 | public boolean acceptsURL(String url) { | |
190 | try { | |
191 | url = mangleURL(url); | |
192 | } catch (SQLException e) { | |
193 | return false; | |
194 | } | |
195 | return super.acceptsURL(url); | |
196 | } | |
197 | ||
198 | ||
199 | /** | |
200 | * Returns our own CVS version plus postgres Version | |
201 | * | |
202 | * @return String value reprenstation of the version | |
203 | */ | |
204 | public static String getVersion() { | |
205 | return "PostGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); | |
206 | } | |
207 | ||
208 | ||
209 | /* | |
210 | * Here follows the addGISTypes() stuff. This is a little tricky because the | |
211 | * pgjdbc people had several, partially incompatible API changes during 7.2 | |
212 | * and 8.0. We still want to support all those releases, however. | |
213 | * | |
214 | */ | |
215 | /** | |
216 | * adds the JTS/PostGIS Data types to a PG 7.3+ Connection. If you use | |
217 | * PostgreSQL jdbc drivers V8.0 or newer, those methods are deprecated due | |
218 | * to some class loader problems (but still work for now), and you may want | |
219 | * to use the method below instead. | |
220 | * | |
221 | * @param pgconn The PGConnection object to add the types to | |
222 | * @throws SQLException when a SQLException occurs | |
223 | * | |
224 | */ | |
225 | public static void addGISTypes(final PGConnection pgconn) throws SQLException { | |
226 | loadTypesAdder("74").addGT((Connection) pgconn, false); | |
227 | } | |
228 | ||
229 | ||
230 | /** | |
231 | * adds the JTS/PostGIS Data types to a PG 8.0+ Connection. | |
232 | * | |
233 | * @param pgconn The PGConnection object to add the types to | |
234 | * @throws SQLException when a SQLException occurs | |
235 | */ | |
236 | public static void addGISTypes80(final PGConnection pgconn) throws SQLException { | |
237 | loadTypesAdder("80").addGT((Connection) pgconn, false); | |
238 | } | |
239 | ||
240 | ||
241 | /** | |
242 | * adds the JTS/PostGIS Data types to a PG 7.2 Connection. | |
243 | * | |
244 | * @param pgconn The PGConnection object to add the types to | |
245 | * @throws SQLException when a SQLException occurs | |
246 | */ | |
247 | public static void addGISTypes72(final org.postgresql.PGConnection pgconn) throws SQLException { | |
248 | loadTypesAdder("72").addGT((Connection) pgconn, false); | |
249 | } | |
250 | ||
251 | ||
252 | /** | |
253 | * Mangles the PostGIS URL to return the original PostGreSQL URL | |
254 | * | |
255 | * @param url String containing the url to be "mangled" | |
256 | * @return "mangled" string | |
257 | * @throws SQLException when a SQLException occurs | |
258 | */ | |
259 | protected String mangleURL(final String url) throws SQLException { | |
260 | String myProgo = getProtoString(); | |
261 | if (url.startsWith(myProgo)) { | |
262 | return POSTGRES_PROTOCOL + url.substring(myProgo.length()); | |
263 | } else { | |
264 | throw new SQLException("Unknown protocol or subprotocol in url " + url); | |
265 | } | |
266 | } | |
267 | ||
268 | ||
269 | protected String getProtoString() { | |
270 | return POSTGIS_PROTOCOL; | |
271 | } | |
272 | ||
273 | ||
274 | /** Base class for the three typewrapper implementations */ | |
275 | protected abstract static class TypesAdder { | |
276 | public final void addGT(final java.sql.Connection conn, final boolean lw) throws SQLException { | |
277 | if (lw) { | |
278 | addBinaryGeometries(conn); | |
279 | } else { | |
280 | addGeometries(conn); | |
281 | } | |
282 | addBoxen(conn); | |
283 | } | |
284 | ||
285 | public abstract void addGeometries(final Connection conn) throws SQLException; | |
286 | ||
287 | public abstract void addBoxen(final Connection conn) throws SQLException; | |
288 | ||
289 | public abstract void addBinaryGeometries(final Connection conn) throws SQLException; | |
290 | } | |
291 | ||
292 | ||
293 | /** addGISTypes for V7.3 and V7.4 pgjdbc */ | |
294 | protected static final class TypesAdder74 extends TypesAdder { | |
295 | ||
296 | /** {@inheritDoc} */ | |
297 | @Override | |
298 | public void addGeometries(final Connection conn) throws SQLException { | |
299 | PGConnection pgconn = (PGConnection) conn; | |
300 | pgconn.addDataType("geometry", net.postgis.jdbc.PGgeometry.class); | |
301 | pgconn.addDataType("public.geometry", net.postgis.jdbc.PGgeometry.class); | |
302 | pgconn.addDataType("\"public\".\"geometry\"", net.postgis.jdbc.PGgeometry.class); | |
303 | ||
304 | pgconn.addDataType("geography", net.postgis.jdbc.PGgeography.class); | |
305 | pgconn.addDataType("public.geography", net.postgis.jdbc.PGgeography.class); | |
306 | pgconn.addDataType("\"public\".\"geography\"", net.postgis.jdbc.PGgeography.class); | |
307 | } | |
308 | ||
309 | /** {@inheritDoc} */ | |
310 | @Override | |
311 | public void addBoxen(final Connection conn) throws SQLException { | |
312 | PGConnection pgconn = (PGConnection) conn; | |
313 | pgconn.addDataType("box3d", net.postgis.jdbc.PGbox3d.class); | |
314 | pgconn.addDataType("box2d", net.postgis.jdbc.PGbox2d.class); | |
315 | } | |
316 | ||
317 | /** {@inheritDoc} */ | |
318 | @Override | |
319 | public void addBinaryGeometries(final Connection conn) throws SQLException { | |
320 | PGConnection pgconn = (PGConnection) conn; | |
321 | pgconn.addDataType("geometry", net.postgis.jdbc.PGgeometryLW.class); | |
322 | pgconn.addDataType("geography", net.postgis.jdbc.PGgeographyLW.class); | |
323 | } | |
324 | } | |
325 | ||
326 | ||
327 | /** addGISTypes for V7.2 pgjdbc */ | |
328 | protected static class TypesAdder72 extends TypesAdder { | |
329 | ||
330 | /** {@inheritDoc} */ | |
331 | @Override | |
332 | public void addGeometries(final Connection conn) throws SQLException { | |
333 | org.postgresql.PGConnection pgconn = (org.postgresql.PGConnection) conn; | |
334 | pgconn.addDataType("geometry", net.postgis.jdbc.PGgeometry.class); | |
335 | pgconn.addDataType("public.geometry", net.postgis.jdbc.PGgeometry.class); | |
336 | pgconn.addDataType("\"public\".\"geometry\"", net.postgis.jdbc.PGgeometry.class); | |
337 | ||
338 | pgconn.addDataType("geography", net.postgis.jdbc.PGgeography.class); | |
339 | pgconn.addDataType("public.geography", net.postgis.jdbc.PGgeography.class); | |
340 | pgconn.addDataType("\"public\".\"geography\"", net.postgis.jdbc.PGgeography.class); | |
341 | } | |
342 | ||
343 | /** {@inheritDoc} */ | |
344 | @Override | |
345 | public void addBoxen(final Connection conn) throws SQLException { | |
346 | org.postgresql.PGConnection pgconn = (org.postgresql.PGConnection) conn; | |
347 | pgconn.addDataType("box3d", net.postgis.jdbc.PGbox3d.class); | |
348 | pgconn.addDataType("box2d", net.postgis.jdbc.PGbox2d.class); | |
349 | } | |
350 | ||
351 | /** {@inheritDoc} */ | |
352 | @Override | |
353 | public void addBinaryGeometries(final Connection conn) throws SQLException { | |
354 | org.postgresql.PGConnection pgconn = (org.postgresql.PGConnection) conn; | |
355 | pgconn.addDataType("geometry", net.postgis.jdbc.PGgeometryLW.class); | |
356 | pgconn.addDataType("geography", net.postgis.jdbc.PGgeographyLW.class); | |
357 | } | |
358 | } | |
359 | ||
360 | ||
361 | /** addGISTypes for V8.0 (and hopefully newer) pgjdbc */ | |
362 | protected static class TypesAdder80 extends TypesAdder { | |
363 | ||
364 | /** {@inheritDoc} */ | |
365 | @Override | |
366 | public void addGeometries(final Connection conn) throws SQLException { | |
367 | PGConnection pgconn = (PGConnection) conn; | |
368 | pgconn.addDataType("geometry", net.postgis.jdbc.PGgeometry.class); | |
369 | pgconn.addDataType("public.geometry", net.postgis.jdbc.PGgeometry.class); | |
370 | pgconn.addDataType("\"public\".\"geometry\"", net.postgis.jdbc.PGgeometry.class); | |
371 | ||
372 | pgconn.addDataType("geography", net.postgis.jdbc.PGgeometry.class); | |
373 | pgconn.addDataType("public.geography", net.postgis.jdbc.PGgeometry.class); | |
374 | pgconn.addDataType("\"public\".\"geography\"", net.postgis.jdbc.PGgeometry.class); | |
375 | } | |
376 | ||
377 | /** {@inheritDoc} */ | |
378 | @Override | |
379 | public void addBoxen(final Connection conn) throws SQLException { | |
380 | PGConnection pgconn = (PGConnection) conn; | |
381 | pgconn.addDataType("box3d", net.postgis.jdbc.PGbox3d.class); | |
382 | pgconn.addDataType("box2d", net.postgis.jdbc.PGbox2d.class); | |
383 | } | |
384 | ||
385 | /** {@inheritDoc} */ | |
386 | @Override | |
387 | public void addBinaryGeometries(final Connection conn) throws SQLException { | |
388 | PGConnection pgconn = (PGConnection) conn; | |
389 | pgconn.addDataType("geometry", net.postgis.jdbc.PGgeometryLW.class); | |
390 | pgconn.addDataType("geography", net.postgis.jdbc.PGgeographyLW.class); | |
391 | } | |
392 | } | |
393 | ||
394 | ||
395 | /** {@inheritDoc} */ | |
396 | @Override | |
397 | public Logger getParentLogger() { | |
398 | throw new UnsupportedOperationException("Not supported yet."); | |
399 | } | |
400 | ||
401 | ||
402 | } |
0 | /* | |
1 | * DriverWrapperAutoprobe.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Wrapper utility class | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package net.postgis.jdbc; | |
26 | ||
27 | import org.postgresql.Driver; | |
28 | ||
29 | import java.sql.Connection; | |
30 | import java.sql.ResultSet; | |
31 | import java.sql.SQLException; | |
32 | import java.sql.Statement; | |
33 | import java.util.logging.Level; | |
34 | ||
35 | /** | |
36 | * DriverWrapperAutoprobe | |
37 | * | |
38 | * Wraps the PostGreSQL Driver to transparently add the PostGIS Object Classes. | |
39 | * This avoids the need of explicit addDataType() calls from the driver users | |
40 | * side. | |
41 | * | |
42 | * This DriverWrapper tries to autoprobe the installed PostGIS version to decide | |
43 | * whether to use EWKT or hex encoded EWKB as canonical text representation. It | |
44 | * uses the first PostGIS installation found in your namespace search path (aka | |
45 | * schema search path) on the server side, and this works as long as you do not | |
46 | * access incompatible PostGIS versions that reside in other schemas. | |
47 | * | |
48 | * For usage notes, see DriverWrapper class, but use "jdbc:postgresql_autogis:" | |
49 | * as JDBC url prefix and net.postgis.jdbc.DriverWrapperAutoprobe as driver class. | |
50 | * | |
51 | * @author {@literal Markus Schaber <markus.schaber@logix-tt.com>} | |
52 | * @see DriverWrapper | |
53 | */ | |
54 | public class DriverWrapperAutoprobe extends DriverWrapper { | |
55 | ||
56 | public static final String POSTGIS_AUTOPROTOCOL = "jdbc:postgresql_autogis:"; | |
57 | public static final String REVISIONAUTO = "$Revision$"; | |
58 | ||
59 | /** | |
60 | * Default constructor. | |
61 | * | |
62 | * @throws SQLException when a SQLExceptin occurs | |
63 | */ | |
64 | public DriverWrapperAutoprobe() throws SQLException { | |
65 | super(); | |
66 | } | |
67 | ||
68 | static { | |
69 | try { | |
70 | // Try to register ourself to the DriverManager | |
71 | java.sql.DriverManager.registerDriver(new DriverWrapperAutoprobe()); | |
72 | } catch (SQLException e) { | |
73 | logger.log(Level.WARNING, "Error registering PostGIS Autoprobe Wrapper Driver", e); | |
74 | } | |
75 | } | |
76 | ||
77 | protected String getProtoString() { | |
78 | return POSTGIS_AUTOPROTOCOL; | |
79 | } | |
80 | ||
81 | protected boolean useLW(Connection conn) { | |
82 | try { | |
83 | return supportsEWKB(conn); | |
84 | } catch (SQLException e) { | |
85 | // fail safe default | |
86 | return false; | |
87 | } | |
88 | } | |
89 | ||
90 | /** | |
91 | * Returns our own CVS version plus postgres Version | |
92 | * | |
93 | * @return String value reprenstation of the version | |
94 | */ | |
95 | public static String getVersion() { | |
96 | return "PostGisWrapperAutoprobe " + REVISIONAUTO + ", wrapping " + Driver.getVersion(); | |
97 | } | |
98 | ||
99 | public static boolean supportsEWKB(Connection conn) throws SQLException { | |
100 | Statement stat = conn.createStatement(); | |
101 | ResultSet rs = stat.executeQuery("SELECT postgis_version()"); | |
102 | rs.next(); | |
103 | String version = rs.getString(1); | |
104 | rs.close(); | |
105 | stat.close(); | |
106 | if (version == null) { | |
107 | throw new SQLException("postgis_version returned NULL!"); | |
108 | } | |
109 | version = version.trim(); | |
110 | int idx = version.indexOf('.'); | |
111 | int majorVersion = Integer.parseInt(version.substring(0, idx)); | |
112 | return majorVersion >= 1; | |
113 | } | |
114 | } |
0 | /* | |
1 | * DriverWrapperLW.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Wrapper utility class | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package net.postgis.jdbc; | |
26 | ||
27 | import org.postgresql.Driver; | |
28 | ||
29 | import java.sql.Connection; | |
30 | import java.sql.SQLException; | |
31 | import java.util.logging.Level; | |
32 | ||
33 | /** | |
34 | * DriverWrapperLW | |
35 | * | |
36 | * Wraps the PostGreSQL Driver to transparently add the PostGIS Object Classes. | |
37 | * This avoids the need of explicit addDataType() calls from the driver users | |
38 | * side. | |
39 | * | |
40 | * This DriverWrapper subclass always uses hex encoded EWKB as canonical text | |
41 | * representation, and thus only works against PostGIS 1.x servers and newer. | |
42 | * | |
43 | * For usage notes, see DriverWrapper class, but use "jdbc:postgresql_lwgis:" as | |
44 | * JDBC url prefix and net.postgis.jdbc.DriverWrapperLW as driver class. | |
45 | * | |
46 | * @author {@literal Markus Schaber <markus.schaber@logix-tt.com>} | |
47 | * @see DriverWrapper | |
48 | */ | |
49 | public class DriverWrapperLW extends DriverWrapper { | |
50 | ||
51 | public static final String POSTGIS_LWPROTOCOL = "jdbc:postgresql_lwgis:"; | |
52 | public static final String REVISIONLW = "$Revision$"; | |
53 | ||
54 | /** | |
55 | * Default constructor. | |
56 | * | |
57 | * @throws SQLException when a SQLException occurs | |
58 | */ | |
59 | public DriverWrapperLW() throws SQLException { | |
60 | super(); | |
61 | } | |
62 | ||
63 | static { | |
64 | try { | |
65 | // Try to register ourself to the DriverManager | |
66 | java.sql.DriverManager.registerDriver(new DriverWrapperLW()); | |
67 | } catch (SQLException e) { | |
68 | logger.log(Level.WARNING, "Error registering PostGIS LW Wrapper Driver", e); | |
69 | } | |
70 | } | |
71 | ||
72 | protected String getProtoString() { | |
73 | return POSTGIS_LWPROTOCOL; | |
74 | } | |
75 | ||
76 | protected boolean useLW(Connection result) { | |
77 | return true; | |
78 | } | |
79 | ||
80 | /** | |
81 | * Returns our own CVS version plus postgres Version | |
82 | * | |
83 | * @return String value reprenstation of the version | |
84 | */ | |
85 | public static String getVersion() { | |
86 | return "PostGisWrapperLW " + REVISIONLW + ", wrapping " + Driver.getVersion(); | |
87 | } | |
88 | } |
0 | /* | |
1 | * PGbox2d.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - bounding box model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc; | |
28 | ||
29 | import net.postgis.jdbc.geometry.Point; | |
30 | ||
31 | import java.sql.SQLException; | |
32 | ||
33 | public class PGbox2d extends PGboxbase { | |
34 | /* JDK 1.5 Serialization */ | |
35 | private static final long serialVersionUID = 0x100; | |
36 | ||
37 | public PGbox2d() { | |
38 | super(); | |
39 | } | |
40 | ||
41 | public PGbox2d(Point llb, Point urt) { | |
42 | super(llb, urt); | |
43 | } | |
44 | ||
45 | public PGbox2d(String value) throws SQLException { | |
46 | super(value); | |
47 | } | |
48 | ||
49 | public void setValue(String value) throws SQLException { | |
50 | super.setValue(value); | |
51 | ||
52 | if (llb.dimension != 2 || urt.dimension != 2) { | |
53 | throw new SQLException("PGbox2d is only allowed to have 2 dimensions!"); | |
54 | } | |
55 | } | |
56 | ||
57 | public String getPrefix() { | |
58 | return "BOX"; | |
59 | } | |
60 | ||
61 | public String getPGtype() { | |
62 | return "box2d"; | |
63 | } | |
64 | ||
65 | protected PGboxbase newInstance() { | |
66 | return new PGbox2d(); | |
67 | } | |
68 | } |
0 | /* | |
1 | * PGbox3d.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - bounding box model | |
4 | * | |
5 | * | |
6 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
7 | * | |
8 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
9 | * | |
10 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
11 | * | |
12 | * This library is free software; you can redistribute it and/or | |
13 | * modify it under the terms of the GNU Lesser General Public | |
14 | * License as published by the Free Software Foundation; either | |
15 | * version 2.1 of the License, or (at your option) any later version. | |
16 | * | |
17 | * This library is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
20 | * Lesser General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU Lesser General Public | |
23 | * License along with this library; if not, write to the Free Software | |
24 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
25 | * | |
26 | */ | |
27 | ||
28 | package net.postgis.jdbc; | |
29 | ||
30 | import net.postgis.jdbc.geometry.Point; | |
31 | ||
32 | import java.sql.SQLException; | |
33 | ||
34 | public class PGbox3d extends PGboxbase { | |
35 | /* JDK 1.5 Serialization */ | |
36 | private static final long serialVersionUID = 0x100; | |
37 | ||
38 | public PGbox3d() { | |
39 | super(); | |
40 | } | |
41 | ||
42 | public PGbox3d(Point llb, Point urt) { | |
43 | super(llb, urt); | |
44 | } | |
45 | ||
46 | public PGbox3d(String value) throws SQLException { | |
47 | super(value); | |
48 | } | |
49 | ||
50 | public String getPrefix() { | |
51 | return ("BOX3D"); | |
52 | } | |
53 | ||
54 | public String getPGtype() { | |
55 | return ("box3d"); | |
56 | } | |
57 | ||
58 | protected PGboxbase newInstance() { | |
59 | return new PGbox3d(); | |
60 | } | |
61 | } |
0 | /* | |
1 | * PGboxbase.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - bounding box model | |
4 | * | |
5 | * | |
6 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
7 | * | |
8 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
9 | * | |
10 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
11 | * | |
12 | * This library is free software; you can redistribute it and/or | |
13 | * modify it under the terms of the GNU Lesser General Public | |
14 | * License as published by the Free Software Foundation; either | |
15 | * version 2.1 of the License, or (at your option) any later version. | |
16 | * | |
17 | * This library is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
20 | * Lesser General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU Lesser General Public | |
23 | * License along with this library; if not, write to the Free Software | |
24 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
25 | * | |
26 | */ | |
27 | ||
28 | package net.postgis.jdbc; | |
29 | ||
30 | import net.postgis.jdbc.geometry.Geometry; | |
31 | import net.postgis.jdbc.geometry.GeometryBuilder; | |
32 | import net.postgis.jdbc.geometry.GeometryTokenizer; | |
33 | import net.postgis.jdbc.geometry.Point; | |
34 | import org.postgresql.util.PGobject; | |
35 | ||
36 | import java.sql.SQLException; | |
37 | import java.util.List; | |
38 | ||
39 | /* | |
40 | * Updates Oct 2002 - data members made private - getLLB() and getURT() methods | |
41 | * added | |
42 | */ | |
43 | ||
44 | public abstract class PGboxbase extends PGobject { | |
45 | /* JDK 1.5 Serialization */ | |
46 | private static final long serialVersionUID = 0x100; | |
47 | ||
48 | /** | |
49 | * The lower left bottom corner of the box. | |
50 | */ | |
51 | protected Point llb; | |
52 | ||
53 | /** | |
54 | * The upper right top corner of the box. | |
55 | */ | |
56 | protected Point urt; | |
57 | ||
58 | /** | |
59 | * The Prefix we have in WKT rep. | |
60 | * | |
61 | * I use an abstract method here so we do not need to replicate the String | |
62 | * object in every instance. | |
63 | * | |
64 | * @return the prefix, as a string | |
65 | */ | |
66 | public abstract String getPrefix(); | |
67 | ||
68 | /** | |
69 | * The Postgres type we have (same construct as getPrefix()) | |
70 | * | |
71 | * @return String containing the name of the type for this box. | |
72 | */ | |
73 | public abstract String getPGtype(); | |
74 | ||
75 | public PGboxbase() { | |
76 | this.setType(getPGtype()); | |
77 | } | |
78 | ||
79 | public PGboxbase(Point llb, Point urt) { | |
80 | this(); | |
81 | this.llb = llb; | |
82 | this.urt = urt; | |
83 | } | |
84 | ||
85 | public PGboxbase(String value) throws SQLException { | |
86 | this(); | |
87 | setValue(value); | |
88 | } | |
89 | ||
90 | public void setValue(String value) throws SQLException { | |
91 | int srid = Geometry.UNKNOWN_SRID; | |
92 | value = value.trim(); | |
93 | if (value.startsWith("SRID=")) { | |
94 | String[] temp = GeometryBuilder.splitSRID(value); | |
95 | value = temp[1].trim(); | |
96 | srid = Geometry.parseSRID(Integer.parseInt(temp[0].substring(5))); | |
97 | } | |
98 | String myPrefix = getPrefix(); | |
99 | if (value.startsWith(myPrefix)) { | |
100 | value = value.substring(myPrefix.length()).trim(); | |
101 | } | |
102 | String valueNoParans = GeometryTokenizer.removeLeadingAndTrailingStrings(value.trim(), "(", ")"); | |
103 | List<String> tokens = GeometryTokenizer.tokenize(valueNoParans, ','); | |
104 | llb = new Point(tokens.get(0)); | |
105 | urt = new Point(tokens.get(1)); | |
106 | if (srid != Geometry.UNKNOWN_SRID) { | |
107 | llb.setSrid(srid); | |
108 | urt.setSrid(srid); | |
109 | } | |
110 | } | |
111 | ||
112 | public String getValue() { | |
113 | StringBuffer sb = new StringBuffer(); | |
114 | outerWKT(sb); | |
115 | return sb.toString(); | |
116 | } | |
117 | ||
118 | private void outerWKT(StringBuffer sb) { | |
119 | sb.append(getPrefix()); | |
120 | sb.append('('); | |
121 | llb.innerWKT(sb); | |
122 | sb.append(','); | |
123 | urt.innerWKT(sb); | |
124 | sb.append(')'); | |
125 | } | |
126 | ||
127 | /** | |
128 | * Unlike geometries, toString() does _not_ contain the srid, as server-side | |
129 | * PostGIS cannot parse this. | |
130 | * | |
131 | * @return String representation of this box | |
132 | */ | |
133 | public String toString() { | |
134 | return getValue(); | |
135 | } | |
136 | ||
137 | /** | |
138 | * Returns the lower left bottom corner of the box as a Point object | |
139 | * | |
140 | * @return lower left bottom corner of this box | |
141 | */ | |
142 | public Point getLLB() { | |
143 | return llb; | |
144 | } | |
145 | ||
146 | /** | |
147 | * Returns the upper right top corner of the box as a Point object | |
148 | * | |
149 | * @return upper right top corner of this box | |
150 | */ | |
151 | public Point getURT() { | |
152 | return urt; | |
153 | } | |
154 | ||
155 | public boolean equals(Object other) { | |
156 | if (other instanceof PGboxbase) { | |
157 | PGboxbase otherbox = (PGboxbase) other; | |
158 | return (compareLazyDim(this.llb, otherbox.llb) && compareLazyDim(this.urt, otherbox.urt)); | |
159 | } | |
160 | return false; | |
161 | } | |
162 | ||
163 | /** | |
164 | * Compare two coordinates with lazy dimension checking. | |
165 | * | |
166 | * As the Server always returns Box3D with three dimensions, z==0 equals | |
167 | * dimensions==2 | |
168 | * | |
169 | * @param first First of two points to be compared | |
170 | * @param second Second of two points to be compared | |
171 | * @return true if the points are the same, false otherwise | |
172 | * | |
173 | */ | |
174 | protected static boolean compareLazyDim(Point first, Point second) { | |
175 | return first.x == second.x | |
176 | && first.y == second.y | |
177 | && (((first.dimension == 2 || first.z == 0.0) && (second.dimension == 2 || second.z == 0)) || (first.z == second.z)); | |
178 | } | |
179 | ||
180 | public Object clone() { | |
181 | PGboxbase obj = newInstance(); | |
182 | obj.llb = this.llb; | |
183 | obj.urt = this.urt; | |
184 | obj.setType(type); | |
185 | return obj; | |
186 | } | |
187 | ||
188 | /** | |
189 | * Obtain a new instance of a PGboxbase | |
190 | * | |
191 | * We could have used this.getClass().newInstance() here, but this forces us | |
192 | * dealing with InstantiationException and IllegalAccessException. Due to | |
193 | * the PGObject.clone() brokennes that does not allow clone() to throw | |
194 | * CloneNotSupportedException, we cannot even pass this exceptions down to | |
195 | * callers in a sane way. | |
196 | * | |
197 | * @return a new instance of PGboxbase | |
198 | */ | |
199 | protected abstract PGboxbase newInstance(); | |
200 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
16 | * | |
17 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
18 | * | |
19 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
20 | */ | |
21 | ||
22 | package net.postgis.jdbc; | |
23 | ||
24 | ||
25 | import net.postgis.jdbc.geometry.Geometry; | |
26 | import net.postgis.jdbc.geometry.GeometryBuilder; | |
27 | import net.postgis.jdbc.geometry.binary.BinaryParser; | |
28 | import org.postgresql.util.PGobject; | |
29 | ||
30 | import java.sql.SQLException; | |
31 | ||
32 | ||
33 | /** | |
34 | * A PostgreSQL JDBC PGobject extension data type modeling a "geo" type. | |
35 | * | |
36 | * This class serves as a common superclass for classes such as PGgeometry and PGgeography which model | |
37 | * more specific type semantics. | |
38 | * | |
39 | * @author Phillip Ross | |
40 | */ | |
41 | public class PGgeo extends PGobject { | |
42 | ||
43 | private static final long serialVersionUID = -3181366908975582090L; | |
44 | ||
45 | /** The encapsulated geometry. */ | |
46 | Geometry geometry; | |
47 | ||
48 | ||
49 | /** Instantiate with default state. */ | |
50 | protected PGgeo() { | |
51 | } | |
52 | ||
53 | ||
54 | /** | |
55 | * Instantiate with the specified state. | |
56 | * | |
57 | * @param geometry the geometry to instantiate with | |
58 | */ | |
59 | public PGgeo(final Geometry geometry) { | |
60 | this(); | |
61 | this.geometry = geometry; | |
62 | } | |
63 | ||
64 | ||
65 | /** | |
66 | * Instantiate with the specified state. | |
67 | * | |
68 | * @param value the value to instantiate with | |
69 | */ | |
70 | public PGgeo(final String value) throws SQLException { | |
71 | this(); | |
72 | setValue(value); | |
73 | } | |
74 | ||
75 | ||
76 | /** {@inheritDoc} */ | |
77 | @Override | |
78 | public String getValue() { | |
79 | return geometry.toString(); | |
80 | } | |
81 | ||
82 | ||
83 | /** {@inheritDoc} */ | |
84 | @Override | |
85 | public void setValue(final String value) throws SQLException { | |
86 | geometry = GeometryBuilder.geomFromString(value, new BinaryParser()); | |
87 | } | |
88 | ||
89 | ||
90 | /** | |
91 | * Get the encapsulated geometry. | |
92 | * | |
93 | * @return the encapsulated geomtery | |
94 | */ | |
95 | public Geometry getGeometry() { | |
96 | return geometry; | |
97 | } | |
98 | ||
99 | ||
100 | /** | |
101 | * Set the encapsulated geometry. | |
102 | * | |
103 | * @param geometry the encapsulated geometry | |
104 | */ | |
105 | public void setGeometry(final Geometry geometry) { | |
106 | this.geometry = geometry; | |
107 | } | |
108 | ||
109 | ||
110 | /** | |
111 | * Get the type of the encapsulated geometry. | |
112 | * | |
113 | * @return the type of the encapsulated geometry | |
114 | */ | |
115 | public int getGeoType() { | |
116 | return geometry.type; | |
117 | } | |
118 | ||
119 | ||
120 | /** {@inheritDoc} */ | |
121 | @Override | |
122 | public String toString() { | |
123 | return geometry.toString(); | |
124 | } | |
125 | ||
126 | ||
127 | /** {@inheritDoc} */ | |
128 | @Override | |
129 | public Object clone() { | |
130 | return new PGgeo(geometry); | |
131 | } | |
132 | ||
133 | ||
134 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
16 | * | |
17 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
18 | * | |
19 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
20 | */ | |
21 | ||
22 | package net.postgis.jdbc; | |
23 | ||
24 | ||
25 | import net.postgis.jdbc.geometry.Geometry; | |
26 | ||
27 | import java.sql.SQLException; | |
28 | ||
29 | ||
30 | /** | |
31 | * A PostgreSQL JDBC PGobject extension data type modeling the geography type. | |
32 | * | |
33 | * @author Phillip Ross | |
34 | */ | |
35 | public class PGgeography extends PGgeo { | |
36 | ||
37 | private static final long serialVersionUID = 3796853960196603896L; | |
38 | ||
39 | ||
40 | /** Instantiate with default state. */ | |
41 | public PGgeography() { | |
42 | super(); | |
43 | setType("geography"); | |
44 | } | |
45 | ||
46 | ||
47 | /** | |
48 | * Instantiate with the specified state. | |
49 | * | |
50 | * @param geometry the geometry to instantiate with | |
51 | */ | |
52 | public PGgeography(final Geometry geometry) { | |
53 | this(); | |
54 | this.geometry = geometry; | |
55 | setType("geography"); | |
56 | } | |
57 | ||
58 | ||
59 | /** | |
60 | * Instantiate with the specified state. | |
61 | * | |
62 | * @param value the value to instantiate with | |
63 | */ | |
64 | public PGgeography(final String value) throws SQLException { | |
65 | this(); | |
66 | setValue(value); | |
67 | setType("geography"); | |
68 | } | |
69 | ||
70 | ||
71 | /** {@inheritDoc} */ | |
72 | @Override | |
73 | public Object clone() { | |
74 | return new PGgeography(geometry); | |
75 | } | |
76 | ||
77 | ||
78 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
16 | * | |
17 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
18 | */ | |
19 | ||
20 | package net.postgis.jdbc; | |
21 | ||
22 | ||
23 | import net.postgis.jdbc.geometry.Geometry; | |
24 | import net.postgis.jdbc.geometry.binary.BinaryWriter; | |
25 | ||
26 | import java.sql.SQLException; | |
27 | ||
28 | ||
29 | /** | |
30 | * A PostgreSQL JDBC PGobject extension data type modeling the geography type. | |
31 | * | |
32 | * The hex-encoded EWKB format is used to communicate with the backend, which is much more efficient, | |
33 | * but only works with Lwgeom enabled PostGIS (1.0.0 and up). | |
34 | * | |
35 | * @author Phillip Ross | |
36 | */ | |
37 | public class PGgeographyLW extends PGgeography { | |
38 | ||
39 | private static final long serialVersionUID = 7717856818804158022L; | |
40 | ||
41 | /** The binary writer to be used for serializing geometry to a PGobject value. */ | |
42 | BinaryWriter bw = new BinaryWriter(); | |
43 | ||
44 | ||
45 | /** Instantiate with default state. */ | |
46 | public PGgeographyLW() { | |
47 | super(); | |
48 | } | |
49 | ||
50 | /** | |
51 | * Instantiate with the specified state. | |
52 | * | |
53 | * @param geometry the geometry to instantiate with | |
54 | */ | |
55 | public PGgeographyLW(final Geometry geometry) { | |
56 | super(geometry); | |
57 | } | |
58 | ||
59 | ||
60 | /** | |
61 | * Instantiate with the specified state. | |
62 | * | |
63 | * @param value the value to instantiate with | |
64 | */ | |
65 | public PGgeographyLW(final String value) throws SQLException { | |
66 | super(value); | |
67 | } | |
68 | ||
69 | ||
70 | /** {@inheritDoc} */ | |
71 | @Override | |
72 | public String getValue() { | |
73 | return bw.writeHexed(geometry); | |
74 | } | |
75 | ||
76 | ||
77 | /** {@inheritDoc} */ | |
78 | @Override | |
79 | public Object clone() { | |
80 | return new PGgeographyLW(geometry); | |
81 | } | |
82 | ||
83 | ||
84 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
16 | * | |
17 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
18 | * | |
19 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
20 | */ | |
21 | ||
22 | package net.postgis.jdbc; | |
23 | ||
24 | ||
25 | import net.postgis.jdbc.geometry.Geometry; | |
26 | ||
27 | import java.sql.SQLException; | |
28 | ||
29 | ||
30 | /** | |
31 | * A PostgreSQL JDBC PGobject extension data type modeling the geometry type. | |
32 | * | |
33 | * @author Phillip Ross | |
34 | */ | |
35 | public class PGgeometry extends PGgeo { | |
36 | ||
37 | private static final long serialVersionUID = 4116907189503026815L; | |
38 | ||
39 | ||
40 | /** Instantiate with default state. */ | |
41 | public PGgeometry() { | |
42 | super(); | |
43 | setType("geometry"); | |
44 | } | |
45 | ||
46 | ||
47 | /** | |
48 | * Instantiate with the specified state. | |
49 | * | |
50 | * @param geometry the geometry to instantiate with | |
51 | */ | |
52 | public PGgeometry(final Geometry geometry) { | |
53 | super(geometry); | |
54 | setType("geometry"); | |
55 | } | |
56 | ||
57 | ||
58 | /** | |
59 | * Instantiate with the specified state. | |
60 | * | |
61 | * @param value the value to instantiate with | |
62 | */ | |
63 | public PGgeometry(final String value) throws SQLException { | |
64 | super(value); | |
65 | setType("geometry"); | |
66 | } | |
67 | ||
68 | ||
69 | /** {@inheritDoc} */ | |
70 | @Override | |
71 | public Object clone() { | |
72 | return new PGgeometry(geometry); | |
73 | } | |
74 | ||
75 | ||
76 | } |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
16 | * | |
17 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
18 | */ | |
19 | ||
20 | package net.postgis.jdbc; | |
21 | ||
22 | ||
23 | import net.postgis.jdbc.geometry.Geometry; | |
24 | import net.postgis.jdbc.geometry.binary.BinaryWriter; | |
25 | ||
26 | import java.sql.SQLException; | |
27 | ||
28 | ||
29 | /** | |
30 | * A PostgreSQL JDBC PGobject extension data type modeling the geometry type. | |
31 | * | |
32 | * The hex-encoded EWKB format is used to communicate with the backend, which is much more efficient, | |
33 | * but only works with Lwgeom enabled PostGIS (1.0.0 and up). | |
34 | * | |
35 | * @author Phillip Ross | |
36 | */ | |
37 | public class PGgeometryLW extends PGgeometry { | |
38 | ||
39 | private static final long serialVersionUID = -7774502289413094862L; | |
40 | ||
41 | /** The binary writer to be used for serializing geometry to a PGobject value. */ | |
42 | BinaryWriter bw = new BinaryWriter(); | |
43 | ||
44 | ||
45 | /** Instantiate with default state. */ | |
46 | public PGgeometryLW() { | |
47 | super(); | |
48 | } | |
49 | ||
50 | ||
51 | /** | |
52 | * Instantiate with the specified state. | |
53 | * | |
54 | * @param geometry the geometry to instantiate with | |
55 | */ | |
56 | public PGgeometryLW(final Geometry geometry) { | |
57 | super(geometry); | |
58 | } | |
59 | ||
60 | ||
61 | /** | |
62 | * Instantiate with the specified state. | |
63 | * | |
64 | * @param value the value to instantiate with | |
65 | */ | |
66 | public PGgeometryLW(final String value) throws SQLException { | |
67 | super(value); | |
68 | } | |
69 | ||
70 | ||
71 | /** {@inheritDoc} */ | |
72 | @Override | |
73 | public String getValue() { | |
74 | return bw.writeHexed(geometry); | |
75 | } | |
76 | ||
77 | ||
78 | /** {@inheritDoc} */ | |
79 | @Override | |
80 | public Object clone() { | |
81 | return new PGgeometryLW(geometry); | |
82 | } | |
83 | ||
84 | ||
85 | } |
0 | /* | |
1 | * Version.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - current version identification | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package net.postgis.jdbc; | |
26 | ||
27 | ||
28 | import java.io.IOException; | |
29 | import java.util.Properties; | |
30 | ||
31 | ||
32 | /** Corresponds to the appropriate PostGIS that carried this source */ | |
33 | public class Version { | |
34 | ||
35 | /** We read our version information from this resource... */ | |
36 | private static final String RESOURCE_FILENAME = "net/postgis/jdbc/version.properties"; | |
37 | ||
38 | private static final String VERSION_PROPERTY_NAME = "VERSION"; | |
39 | ||
40 | public static final String VERSION; | |
41 | ||
42 | /** The major version */ | |
43 | public static final int MAJOR; | |
44 | ||
45 | /** The minor version */ | |
46 | public static final int MINOR; | |
47 | ||
48 | /** | |
49 | * The micro version, usually a number including possibly textual suffixes | |
50 | * like RC3. | |
51 | */ | |
52 | public static final String MICRO; | |
53 | ||
54 | static { | |
55 | int major = -1; | |
56 | int minor = -1; | |
57 | String micro = null; | |
58 | String version = null; | |
59 | try { | |
60 | ClassLoader loader = Version.class.getClassLoader(); | |
61 | ||
62 | Properties prop = new Properties(); | |
63 | try { | |
64 | prop.load(loader.getResourceAsStream(RESOURCE_FILENAME)); | |
65 | } catch (IOException e) { | |
66 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version. Cause: Ressource " | |
67 | + RESOURCE_FILENAME + " cannot be read. " + e.getMessage()); | |
68 | } catch (NullPointerException e) { | |
69 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version. Cause: Ressource " | |
70 | + RESOURCE_FILENAME + " not found. " + e.getMessage()); | |
71 | } | |
72 | ||
73 | version = prop.getProperty(VERSION_PROPERTY_NAME); | |
74 | if (version == null) { | |
75 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version: Missing " + VERSION_PROPERTY_NAME + " property."); | |
76 | } else if (version.equals("")) { | |
77 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version: Empty " + VERSION_PROPERTY_NAME + " property."); | |
78 | } else { | |
79 | String[] versions = version.split("\\."); | |
80 | if (version.length() < 3) { | |
81 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version: FULL_VERSION (" + version + ") does not contain 3 components "); | |
82 | } | |
83 | if (versions.length >= 1) { | |
84 | try { | |
85 | major = Integer.parseInt(versions[0]); | |
86 | } catch (NumberFormatException nfe) { | |
87 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version! Error parsing major version "); | |
88 | } | |
89 | } | |
90 | if (versions.length >= 2) { | |
91 | try { | |
92 | minor = Integer.parseInt(versions[1]); | |
93 | } catch (NumberFormatException nfe) { | |
94 | throw new ExceptionInInitializerError("Error initializing PostGIS JDBC version! Error parsing minor version "); | |
95 | } | |
96 | } | |
97 | if (version.length() >= 3) { | |
98 | micro = versions[2]; | |
99 | } | |
100 | } | |
101 | ||
102 | } finally { | |
103 | MAJOR = major; | |
104 | MINOR = minor; | |
105 | MICRO = micro; | |
106 | VERSION = version; | |
107 | } | |
108 | } | |
109 | ||
110 | /** Full version for human reading - code should use the constants above */ | |
111 | public static final String FULL = "PostGIS JDBC V" + MAJOR + "." + MINOR + "." + MICRO; | |
112 | ||
113 | public static String getFullVersion() { | |
114 | return FULL; | |
115 | } | |
116 | ||
117 | ||
118 | }⏎ |
0 | <body> | |
1 | <p>The JDBC extensions provide Java objects corresponding to the internal PostGIS types. These objects can be used | |
2 | to write Java clients which query the PostGIS database and draw or do calculations on the GIS data in PostGIS. | |
3 | </p> | |
4 | </body>⏎ |
0 | net.postgis.jdbc.DriverWrapper | |
1 | net.postgis.jdbc.DriverWrapperAutoprobe | |
2 | net.postgis.jdbc.DriverWrapperLW |
0 | # | |
1 | # This property file is included in the postgis jar and autoregisters the | |
2 | # PostGIS datatypes within the jdbc driver. | |
3 | # | |
4 | ||
5 | datatype.geometry=net.postgis.jdbc.PGgeometry | |
6 | datatype.geography=net.postgis.jdbc.PGgeography | |
7 | datatype.box3d=net.postgis.jdbc.PGbox3d | |
8 | datatype.box2d=net.postgis.jdbc.PGbox2d |
0 | VERSION=${version}⏎ |
0 | /* | |
1 | * BoxesTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc; | |
28 | ||
29 | ||
30 | import net.postgis.tools.testutils.TestContainerController; | |
31 | import net.postgis.jdbc.geometry.util.VersionUtil; | |
32 | import org.postgresql.util.PGobject; | |
33 | import org.slf4j.Logger; | |
34 | import org.slf4j.LoggerFactory; | |
35 | import org.testng.Assert; | |
36 | import org.testng.ITestContext; | |
37 | import org.testng.annotations.AfterClass; | |
38 | import org.testng.annotations.BeforeClass; | |
39 | import org.testng.annotations.Test; | |
40 | ||
41 | import java.sql.*; | |
42 | ||
43 | ||
44 | public class BoxesTest { | |
45 | ||
46 | private static final Logger logger = LoggerFactory.getLogger(BoxesTest.class); | |
47 | ||
48 | /** Our test candidates: */ | |
49 | public static final String[] BOXEN3D = new String[]{ | |
50 | "BOX3D(1 2 3,4 5 6)", // 3d variant | |
51 | "BOX3D(1 2,4 5)"// 2d variant | |
52 | }; | |
53 | ||
54 | public static final String[] BOXEN2D = new String[]{"BOX(1 2,3 4)"}; | |
55 | ||
56 | private Connection connection = null; | |
57 | ||
58 | ||
59 | @Test | |
60 | public void testBoxes() throws Exception { | |
61 | for (String aBOXEN3D : BOXEN3D) { | |
62 | PGbox3d candidate = new PGbox3d(aBOXEN3D); | |
63 | test(aBOXEN3D, candidate, false); | |
64 | } | |
65 | for (String aBOXEN2D : BOXEN2D) { | |
66 | PGbox2d candidate = new PGbox2d(aBOXEN2D); | |
67 | test(aBOXEN2D, candidate, true); | |
68 | } | |
69 | } | |
70 | ||
71 | ||
72 | public void test(String orig, PGobject candidate, boolean newPostgisOnly) throws Exception { | |
73 | logger.debug("Original: {}", orig); | |
74 | String redone = candidate.toString(); | |
75 | logger.debug("Parsed: {}", redone); | |
76 | Assert.assertEquals(orig, redone, "Recreated Text Rep not equal"); | |
77 | ||
78 | // Simulate the way postgresql-jdbc uses to create PGobjects | |
79 | PGobject recreated = candidate.getClass().newInstance(); | |
80 | recreated.setValue(redone); | |
81 | ||
82 | String reparsed = recreated.toString(); | |
83 | logger.debug("Re-Parsed: " + reparsed); | |
84 | Assert.assertEquals(recreated, candidate, "Recreated boxen are not equal"); | |
85 | Assert.assertEquals(reparsed, orig, "2nd generation text reps are not equal"); | |
86 | ||
87 | logger.debug("testing on connection: {}", connection.getCatalog()); | |
88 | Statement statement = connection.createStatement(); | |
89 | if (newPostgisOnly && Integer.parseInt(VersionUtil.retrievePostGISServerMajorVersion(connection)) < 1) { | |
90 | logger.debug("PostGIS version is too old, not testing box2d"); | |
91 | } else { | |
92 | PGobject sqlGeom = viaSQL(candidate, statement); | |
93 | logger.debug("SQLin : " + sqlGeom.toString()); | |
94 | Assert.assertEquals(candidate, sqlGeom, "Geometries after SQL are not equal"); | |
95 | PGobject sqlreGeom = viaSQL(recreated, statement); | |
96 | logger.debug("SQLout : " + sqlreGeom.toString()); | |
97 | Assert.assertEquals(candidate, sqlreGeom, "reparsed Geometries after SQL are not equal"); | |
98 | } | |
99 | statement.close(); | |
100 | } | |
101 | ||
102 | ||
103 | /** Pass a geometry representation through the SQL server */ | |
104 | private static PGobject viaSQL(PGobject obj, Statement stat) throws SQLException { | |
105 | ResultSet rs = stat.executeQuery("SELECT '" + obj.toString() + "'::" + obj.getType()); | |
106 | rs.next(); | |
107 | return (PGobject) rs.getObject(1); | |
108 | } | |
109 | ||
110 | ||
111 | @BeforeClass | |
112 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
113 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
114 | Assert.assertNotNull(jdbcUrlSuffix); | |
115 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
116 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
117 | Assert.assertNotNull(jdbcUsername); | |
118 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
119 | Assert.assertNotNull(jdbcPassword); | |
120 | Class.forName("net.postgis.jdbc.DriverWrapper"); | |
121 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
122 | } | |
123 | ||
124 | ||
125 | @AfterClass | |
126 | public void shutdown() throws Exception { | |
127 | logger.debug("shutting down"); | |
128 | if (connection != null) { | |
129 | connection.close(); | |
130 | } | |
131 | } | |
132 | ||
133 | ||
134 | }⏎ |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
16 | * | |
17 | * (C) 2020 Phillip Ross, phillip.w.g.ross@gmail.com | |
18 | */ | |
19 | ||
20 | package net.postgis.jdbc; | |
21 | ||
22 | ||
23 | import net.postgis.tools.testutils.TestContainerController; | |
24 | import net.postgis.jdbc.geometry.util.VersionUtil; | |
25 | import org.postgresql.Driver; | |
26 | import org.postgresql.util.PGobject; | |
27 | import org.slf4j.Logger; | |
28 | import org.slf4j.LoggerFactory; | |
29 | import org.testng.Assert; | |
30 | import org.testng.ITestContext; | |
31 | import org.testng.annotations.AfterMethod; | |
32 | import org.testng.annotations.BeforeMethod; | |
33 | import org.testng.annotations.Test; | |
34 | ||
35 | import java.sql.Connection; | |
36 | import java.sql.DriverManager; | |
37 | import java.sql.ResultSet; | |
38 | import java.sql.Statement; | |
39 | ||
40 | ||
41 | /** | |
42 | * This test program tests whether the auto-registration of PostGIS data types within the postgresql jdbc driver was | |
43 | * successful. It also checks for PostGIS version to know whether box2d is available. | |
44 | */ | |
45 | public class DatatypesAutoRegistrationTest { | |
46 | ||
47 | /** The static logger instance. */ | |
48 | private static final Logger logger = LoggerFactory.getLogger(DatatypesAutoRegistrationTest.class); | |
49 | ||
50 | /** The JDBC Connection to be used for tests. */ | |
51 | private Connection connection; | |
52 | ||
53 | ||
54 | /** | |
55 | * Initializes a new JDBC Connection. | |
56 | * | |
57 | * @param ctx the test context | |
58 | * @throws Exception when an exception occurs | |
59 | */ | |
60 | @BeforeMethod | |
61 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
62 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
63 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
64 | Assert.assertNotNull(jdbcUrlSuffix); | |
65 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
66 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
67 | Assert.assertNotNull(jdbcUsername); | |
68 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
69 | Assert.assertNotNull(jdbcPassword); | |
70 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
71 | } | |
72 | ||
73 | ||
74 | /** | |
75 | * Un-allocates the JDBC connection. | |
76 | * | |
77 | * @throws Exception when an exception occurs | |
78 | */ | |
79 | @AfterMethod | |
80 | public void shutdown() throws Exception { | |
81 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
82 | logger.debug("shutting down"); | |
83 | if (connection != null) { | |
84 | connection.close(); | |
85 | } | |
86 | } | |
87 | ||
88 | ||
89 | @Test | |
90 | public void testAutoRegistration() throws Exception { | |
91 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
92 | Driver driver = new Driver(); | |
93 | int driverMajorVersion = driver.getMajorVersion(); | |
94 | int driverMinorVersion = driver.getMinorVersion(); | |
95 | logger.debug("Driver version: {}.{}", driverMajorVersion, driverMinorVersion); | |
96 | if (driverMajorVersion < 8) { | |
97 | logger.info( | |
98 | "postgresql driver {}.{} is too old, it does not support auto-registration", | |
99 | driverMajorVersion, driverMinorVersion | |
100 | ); | |
101 | } else { | |
102 | int postgisServerMajor = Integer.parseInt(VersionUtil.retrievePostGISServerMajorVersion(connection)); | |
103 | logger.debug("PostGIS Version: " + postgisServerMajor); | |
104 | Assert.assertNotEquals( | |
105 | postgisServerMajor, | |
106 | 0, | |
107 | "Could not get PostGIS version. Is PostGIS really installed in the database?" | |
108 | ); | |
109 | Statement statement = connection.createStatement(); | |
110 | ||
111 | // Test geometries | |
112 | ResultSet resultSet = statement.executeQuery("SELECT 'POINT(1 2)'::geometry"); | |
113 | resultSet.next(); | |
114 | PGobject result = (PGobject) resultSet.getObject(1); | |
115 | Assert.assertTrue(result instanceof PGgeometry); | |
116 | ||
117 | // Test geography | |
118 | resultSet = statement.executeQuery("SELECT 'POINT(1 2)'::geography"); | |
119 | resultSet.next(); | |
120 | Object geographyRawObject = resultSet.getObject(1); | |
121 | result = (PGobject) resultSet.getObject(1); | |
122 | Assert.assertTrue(result instanceof PGgeography); | |
123 | ||
124 | // Test box3d | |
125 | resultSet = statement.executeQuery("SELECT 'BOX3D(1 2 3, 4 5 6)'::box3d"); | |
126 | resultSet.next(); | |
127 | result = (PGobject) resultSet.getObject(1); | |
128 | Assert.assertTrue(result instanceof PGbox3d); | |
129 | ||
130 | // Test box2d if appropriate | |
131 | if (postgisServerMajor < 1) { | |
132 | logger.info("PostGIS version is too old, skipping box2ed test"); | |
133 | } else { | |
134 | resultSet = statement.executeQuery("SELECT 'BOX(1 2,3 4)'::box2d"); | |
135 | resultSet.next(); | |
136 | result = (PGobject) resultSet.getObject(1); | |
137 | Assert.assertTrue(result instanceof PGbox2d); | |
138 | } | |
139 | } | |
140 | } | |
141 | ||
142 | ||
143 | } |
0 | /* | |
1 | * DatatypesTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc; | |
28 | ||
29 | ||
30 | import org.slf4j.Logger; | |
31 | import org.slf4j.LoggerFactory; | |
32 | import org.testng.annotations.Test; | |
33 | ||
34 | import java.sql.SQLException; | |
35 | ||
36 | ||
37 | public class DatatypesTest { | |
38 | ||
39 | private static final Logger logger = LoggerFactory.getLogger(DatatypesTest.class); | |
40 | ||
41 | private static final String mlng_str = "MULTILINESTRING ((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"; | |
42 | ||
43 | ||
44 | @Test | |
45 | public void testPGgeometry() throws SQLException { | |
46 | logger.trace("void testPGgeometry()"); | |
47 | logger.info(mlng_str); | |
48 | PGgeometry pgf = new PGgeometry(mlng_str); | |
49 | logger.info(pgf.toString()); | |
50 | } | |
51 | ||
52 | ||
53 | @Test | |
54 | public void testPGgeography() throws SQLException { | |
55 | logger.trace("void testPGgeography()"); | |
56 | logger.info(mlng_str); | |
57 | PGgeography pgf = new PGgeography(mlng_str); | |
58 | logger.info(pgf.toString()); | |
59 | } | |
60 | ||
61 | ||
62 | }⏎ |
0 | /* | |
1 | * EmptyGeometriesTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | * | |
21 | */ | |
22 | ||
23 | package net.postgis.jdbc; | |
24 | ||
25 | ||
26 | import net.postgis.tools.testutils.TestContainerController; | |
27 | import org.slf4j.Logger; | |
28 | import org.slf4j.LoggerFactory; | |
29 | import org.testng.Assert; | |
30 | import org.testng.ITestContext; | |
31 | import org.testng.annotations.AfterClass; | |
32 | import org.testng.annotations.BeforeClass; | |
33 | import org.testng.annotations.Test; | |
34 | ||
35 | import java.sql.*; | |
36 | import java.util.ArrayList; | |
37 | import java.util.List; | |
38 | ||
39 | ||
40 | /** | |
41 | * This class contains tests for handling of empty geometries. | |
42 | * | |
43 | * @author Phillip Ross {@literal <phillip.r.g.ross@gmail.com>} | |
44 | */ | |
45 | public class EmptyGeometriesTest { | |
46 | ||
47 | private static final Logger logger = LoggerFactory.getLogger(EmptyGeometriesTest.class); | |
48 | ||
49 | private static final String DRIVER_WRAPPER_CLASS_NAME = "net.postgis.jdbc.DriverWrapper"; | |
50 | ||
51 | private static final String DRIVER_WRAPPER_AUTOPROBE_CLASS_NAME = "net.postgis.jdbc.DriverWrapperAutoprobe"; | |
52 | ||
53 | ||
54 | public static final String[] geometriesToTest = new String[] { | |
55 | "POINT", | |
56 | "LINESTRING", | |
57 | "POLYGON", | |
58 | "MULTIPOINT", | |
59 | "MULTILINESTRING", | |
60 | "MULTIPOLYGON", | |
61 | "GEOMETRYCOLLECTION", | |
62 | }; | |
63 | ||
64 | public static final String[] castTypes = new String[] { | |
65 | "bytea", | |
66 | "text", | |
67 | "geometry", | |
68 | "geography" | |
69 | }; | |
70 | ||
71 | private Connection connection = null; | |
72 | ||
73 | private Statement statement = null; | |
74 | ||
75 | ||
76 | @Test | |
77 | public void testSqlStatements() throws SQLException { | |
78 | for (String sqlStatement : generateSqlStatements()) { | |
79 | logger.debug("**********"); | |
80 | logger.debug("* Executing sql statemnent => [{}]", sqlStatement); | |
81 | logger.debug("**********"); | |
82 | try (PreparedStatement preparedStatement = connection.prepareStatement(sqlStatement); | |
83 | ResultSet resultSet = preparedStatement.executeQuery() | |
84 | ) { | |
85 | resultSet.next(); | |
86 | for (int i = 1; i <= castTypes.length; i++) { | |
87 | Object resultSetObject = resultSet.getObject(i); | |
88 | logger.debug("returned resultSetObject {} => (class=[{}]) {}", i, resultSetObject.getClass().getName(), resultSetObject); | |
89 | } | |
90 | resultSet.close(); | |
91 | } | |
92 | } | |
93 | } | |
94 | ||
95 | ||
96 | private List<String> generateSqlStatements() { | |
97 | List<String> sqlStatementList = new ArrayList<>(); | |
98 | for (String geometry : geometriesToTest) { | |
99 | StringBuilder stringBuilder = new StringBuilder("select "); | |
100 | for (String castType : castTypes) { | |
101 | stringBuilder.append("geometry_in('") | |
102 | .append(geometry) | |
103 | .append(" EMPTY')::") | |
104 | .append(castType) | |
105 | .append(", "); | |
106 | } | |
107 | String sqlStatement = stringBuilder.substring(0, stringBuilder.lastIndexOf(",")); | |
108 | logger.debug("generate sql statement: {}", sqlStatement); | |
109 | sqlStatementList.add(sqlStatement); | |
110 | } | |
111 | return sqlStatementList; | |
112 | } | |
113 | ||
114 | ||
115 | @BeforeClass | |
116 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
117 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
118 | Assert.assertNotNull(jdbcUrlSuffix); | |
119 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
120 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
121 | Assert.assertNotNull(jdbcUsername); | |
122 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
123 | Assert.assertNotNull(jdbcPassword); | |
124 | Class.forName(DRIVER_WRAPPER_CLASS_NAME); | |
125 | Class.forName(DRIVER_WRAPPER_AUTOPROBE_CLASS_NAME); | |
126 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
127 | statement = connection.createStatement(); | |
128 | } | |
129 | ||
130 | ||
131 | @AfterClass | |
132 | public void unallocateDatabaseResources() throws Exception { | |
133 | if ((statement != null) && (!statement.isClosed())) { | |
134 | statement.close(); | |
135 | } | |
136 | if ((connection != null) && (!connection.isClosed())) { | |
137 | connection.close(); | |
138 | } | |
139 | } | |
140 | ||
141 | ||
142 | }⏎ |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2020 Phillip Ross, phillip.w.g.ross@gmail.com | |
16 | */ | |
17 | ||
18 | package net.postgis.jdbc; | |
19 | ||
20 | ||
21 | import net.postgis.tools.testutils.TestContainerController; | |
22 | import org.slf4j.Logger; | |
23 | import org.slf4j.LoggerFactory; | |
24 | import org.testng.Assert; | |
25 | import org.testng.ITestContext; | |
26 | import org.testng.annotations.AfterMethod; | |
27 | import org.testng.annotations.BeforeMethod; | |
28 | import org.testng.annotations.Test; | |
29 | ||
30 | import java.sql.Connection; | |
31 | import java.sql.DatabaseMetaData; | |
32 | import java.sql.DriverManager; | |
33 | import java.sql.PreparedStatement; | |
34 | import java.sql.ResultSet; | |
35 | import java.sql.Statement; | |
36 | import java.util.UUID; | |
37 | ||
38 | ||
39 | /** | |
40 | * Integration tests for PGgeography. | |
41 | * | |
42 | * @author Phillip Ross | |
43 | */ | |
44 | public class GeographyDatatypeTest { | |
45 | ||
46 | /** The static logger instance. */ | |
47 | private static final Logger logger = LoggerFactory.getLogger(GeographyDatatypeTest.class); | |
48 | ||
49 | /** The jdbc url prefix containing the jdbc protocol to be used for tests. */ | |
50 | private static final String JDBC_URL_PROTOCOL_PREFIX = "jdbc:postgresql"; | |
51 | ||
52 | /** The jdbc url prefix containing the jdbc lightweight protocol to be used for tests. */ | |
53 | private static final String JDBC_URL_LW_PROTOCOL_PREFIX = "jdbc:postgresql_lwgis"; | |
54 | ||
55 | /** The prefix for database tables used in the tests. */ | |
56 | private static final String DATABASE_TABLE_NAME_PREFIX = "jdbc_test"; | |
57 | ||
58 | /** Test geometries dataset. */ | |
59 | public static final String[] testGeometries = new String[] { | |
60 | "POINT(10 10)", // 2D | |
61 | "POINT(10 10 0)", // 3D with 3rd coordinate set to 0 | |
62 | "POINT(10 10 20)", // 3D | |
63 | "POINT(1e100 1.2345e-100 -2e-5)", // 3D with scientific notation | |
64 | "POINTM(10 10 20)", // 2D + Measures | |
65 | "POINT(10 10 20 30)", // 3D + Measures | |
66 | "MULTIPOINT(11 12, 20 20)", // broken format, see http://lists.jump-project.org/pipermail/jts-devel/2006-April/001572.html | |
67 | "MULTIPOINT(11 12 13, 20 20 20)", // broken format | |
68 | "MULTIPOINTM(11 12 13, 20 20 20)", // broken format | |
69 | "MULTIPOINT(11 12 13 14,20 20 20 20)", // broken format | |
70 | "MULTIPOINT((11 12), (20 20))", // OGC conforming format | |
71 | "MULTIPOINT((11 12 13), (20 20 20))", | |
72 | "MULTIPOINTM((11 12 13), (20 20 20))", | |
73 | "MULTIPOINT((11 12 13 14),(20 20 20 20))", | |
74 | "LINESTRING(10 10,20 20,50 50,34 34)", | |
75 | "LINESTRING(10 10 20,20 20 20,50 50 50,34 34 34)", | |
76 | "LINESTRINGM(10 10 20,20 20 20,50 50 50,34 34 34)", | |
77 | "LINESTRING(10 10 20 20,20 20 20 20,50 50 50 50,34 34 34 50)", | |
78 | "POLYGON((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))", | |
79 | "POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", | |
80 | "POLYGONM((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", | |
81 | "POLYGON((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7))", | |
82 | "MULTIPOLYGON(((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)),((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)))", | |
83 | "MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", | |
84 | "MULTIPOLYGONM(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", | |
85 | "MULTIPOLYGON(((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7)),((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7)))", | |
86 | "MULTILINESTRING((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))", | |
87 | "MULTILINESTRING((10 10 5,20 10 5,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", | |
88 | "MULTILINESTRINGM((10 10 7,20 10 7,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))", | |
89 | "MULTILINESTRING((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7))", | |
90 | "GEOMETRYCOLLECTION(POINT(10 10),POINT(20 20))", | |
91 | "GEOMETRYCOLLECTION(POINT(10 10 20),POINT(20 20 20))", | |
92 | "GEOMETRYCOLLECTION(POINT(10 10 20 7),POINT(20 20 20 7))", | |
93 | "GEOMETRYCOLLECTION(LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34))", | |
94 | "GEOMETRYCOLLECTION(POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", | |
95 | "GEOMETRYCOLLECTION(MULTIPOINT(10 10 10, 20 20 20),MULTIPOINT(10 10 10, 20 20 20))", // Cannot be parsed by 0.X servers, broken format | |
96 | "GEOMETRYCOLLECTION(MULTIPOINT((10 10 10), (20 20 20)),MULTIPOINT((10 10 10), (20 20 20)))", // Cannot be parsed by 0.X servers, OGC conformant | |
97 | "GEOMETRYCOLLECTION(MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", // PostGIs 0.X "flattens" this geometry, so it is not equal after reparsing. | |
98 | "GEOMETRYCOLLECTION(MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))))", // PostGIs 0.X "flattens" this geometry, so it is not equal after reparsing. | |
99 | "GEOMETRYCOLLECTION(POINT(10 10 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", | |
100 | "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT(10 10 10, 20 20 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", // Collections that contain both X and MultiX do not work on PostGIS 0.x, broken format | |
101 | "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT((10 10 10), (20 20 20)),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))", // Collections that contain both X and MultiX do not work on PostGIS 0.x, OGC conformant | |
102 | "GEOMETRYCOLLECTION EMPTY", // new (correct) representation | |
103 | "GEOMETRYCOLLECTIONM(POINTM(10 10 20),POINTM(20 20 20))" | |
104 | }; | |
105 | ||
106 | /** The JDBC Connection to be used for tests. */ | |
107 | private Connection connection = null; | |
108 | ||
109 | /** The JDBC Connection w/ lightweight protocol to be used for tests. */ | |
110 | private Connection connectionLW = null; | |
111 | ||
112 | ||
113 | /** | |
114 | * Initializes a new JDBC Connection. | |
115 | * | |
116 | * @param ctx the test context | |
117 | * @throws Exception when an exception occurs | |
118 | */ | |
119 | @BeforeMethod | |
120 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
121 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
122 | Assert.assertNotNull(jdbcUrlSuffix); | |
123 | final String jdbcUrl = JDBC_URL_PROTOCOL_PREFIX + jdbcUrlSuffix; | |
124 | final String jdbcUrlLW = JDBC_URL_LW_PROTOCOL_PREFIX + jdbcUrlSuffix; | |
125 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
126 | Assert.assertNotNull(jdbcUsername); | |
127 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
128 | Assert.assertNotNull(jdbcPassword); | |
129 | Class.forName("net.postgis.jdbc.DriverWrapperLW"); | |
130 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
131 | connectionLW = DriverManager.getConnection(jdbcUrlLW, jdbcUsername, jdbcPassword); | |
132 | } | |
133 | ||
134 | ||
135 | /** | |
136 | * Un-allocates the JDBC connection. | |
137 | * | |
138 | * @throws Exception when an exception occurs | |
139 | */ | |
140 | @AfterMethod | |
141 | public void unallocateDatabaseResources() throws Exception { | |
142 | if ((connection != null) && (!connection.isClosed())) { | |
143 | connection.close(); | |
144 | } | |
145 | if ((connectionLW != null) && (!connectionLW.isClosed())) { | |
146 | connection.close(); | |
147 | } | |
148 | } | |
149 | ||
150 | ||
151 | /** | |
152 | * Test inserting geometries into the database with prepared statements and querying back the results with | |
153 | * both geometry/geography and standard/lightweight. | |
154 | * | |
155 | * @throws Exception when an exception occurs. | |
156 | */ | |
157 | @Test | |
158 | public void testDatatypes() throws Exception { | |
159 | ||
160 | final String testTableName = DATABASE_TABLE_NAME_PREFIX | |
161 | + "_" | |
162 | + UUID.randomUUID() | |
163 | .toString() | |
164 | .replaceAll("-", ""); | |
165 | ||
166 | final String dropTableSQL = "drop table " + testTableName; | |
167 | ||
168 | final String createTableSQL = "create table " + testTableName | |
169 | + " ( _id numeric," | |
170 | + " geometry_value geometry, geometrylw_value geometry," | |
171 | + " geography_value geography, geographylw_value geography)"; | |
172 | final int idColumnIndex = 1; | |
173 | final int geometryValueColumnIndex = 2; | |
174 | final int geometrylwValueColumnIndex = 3; | |
175 | final int geographyValueColumnIndex = 4; | |
176 | final int geographylwValueColumnIndex = 5; | |
177 | ||
178 | final String insertSQL = "insert into " + testTableName + " ( " | |
179 | + "_id, geometry_value, geometrylw_value, " | |
180 | + "geography_value, geographylw_value) " | |
181 | + "values ( ?, ?, ?, ?, ? )"; | |
182 | ||
183 | boolean tableExists = false; | |
184 | DatabaseMetaData databaseMetaData = connection.getMetaData(); | |
185 | try ( | |
186 | ResultSet resultSet = databaseMetaData.getTables( | |
187 | null, null, testTableName.toLowerCase(), new String[] { "TABLE" } | |
188 | ) | |
189 | ) { | |
190 | while (resultSet.next()) { | |
191 | tableExists = true; | |
192 | } | |
193 | } | |
194 | ||
195 | if (tableExists) { | |
196 | logger.debug("Dropping pre-existing test table..."); | |
197 | try (Statement statement = connection.createStatement()) { | |
198 | statement.executeQuery(dropTableSQL); | |
199 | } | |
200 | } | |
201 | ||
202 | logger.debug("Creating test table..."); | |
203 | try (Statement statement = connection.createStatement()) { | |
204 | statement.execute(createTableSQL); | |
205 | } | |
206 | ||
207 | ||
208 | logger.debug("Inserting test geometries into table..."); | |
209 | try (PreparedStatement preparedStatement = connection.prepareStatement(insertSQL)) { | |
210 | for (int i = 0; i < testGeometries.length; i++) { | |
211 | PGgeometry geometry = new PGgeometry(testGeometries[i]); | |
212 | PGgeometryLW geometryLW = new PGgeometryLW(testGeometries[i]); | |
213 | PGgeography geography = new PGgeography(testGeometries[i]); | |
214 | PGgeographyLW geographyLW = new PGgeographyLW(testGeometries[i]); | |
215 | ||
216 | preparedStatement.setInt(idColumnIndex, i); | |
217 | preparedStatement.setObject(geometryValueColumnIndex, geometry); | |
218 | preparedStatement.setObject(geometrylwValueColumnIndex, geometryLW); | |
219 | preparedStatement.setObject(geographyValueColumnIndex, geography); | |
220 | preparedStatement.setObject(geographylwValueColumnIndex, geographyLW); | |
221 | preparedStatement.executeUpdate(); | |
222 | } | |
223 | } | |
224 | ||
225 | logger.debug("Querying table with standard connection..."); | |
226 | try ( | |
227 | Statement statement = connection.createStatement(); | |
228 | ResultSet resultSet = statement.executeQuery( | |
229 | "select _id, geometry_value, geometrylw_value, geography_value, geographylw_value from " | |
230 | + testTableName | |
231 | ) | |
232 | ) { | |
233 | while (resultSet.next()) { | |
234 | Assert.assertEquals(resultSet.getObject(geometryValueColumnIndex).getClass(), PGgeometry.class); | |
235 | Assert.assertEquals(resultSet.getObject(geometrylwValueColumnIndex).getClass(), PGgeometry.class); | |
236 | Assert.assertEquals(resultSet.getObject(geographyValueColumnIndex).getClass(), PGgeography.class); | |
237 | Assert.assertEquals(resultSet.getObject(geographylwValueColumnIndex).getClass(), PGgeography.class); | |
238 | } | |
239 | } | |
240 | ||
241 | logger.debug("Querying table with lightweight connection..."); | |
242 | try ( | |
243 | Statement statement = connectionLW.createStatement(); | |
244 | ResultSet resultSet = statement.executeQuery( | |
245 | "select _id, geometry_value, geometrylw_value, geography_value, geographylw_value from " | |
246 | + testTableName | |
247 | ) | |
248 | ) { | |
249 | while (resultSet.next()) { | |
250 | Assert.assertEquals(resultSet.getObject(geometryValueColumnIndex).getClass(), PGgeometryLW.class); | |
251 | Assert.assertEquals(resultSet.getObject(geometrylwValueColumnIndex).getClass(), PGgeometryLW.class); | |
252 | Assert.assertEquals(resultSet.getObject(geographyValueColumnIndex).getClass(), PGgeographyLW.class); | |
253 | Assert.assertEquals(resultSet.getObject(geographylwValueColumnIndex).getClass(), PGgeographyLW.class); | |
254 | } | |
255 | } | |
256 | } | |
257 | ||
258 | ||
259 | }⏎ |
0 | /* | |
1 | * ParserTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc; | |
28 | ||
29 | ||
30 | import net.postgis.jdbc.geometry.Geometry; | |
31 | import net.postgis.jdbc.geometry.GeometryBuilder; | |
32 | import net.postgis.jdbc.geometry.binary.BinaryParser; | |
33 | import net.postgis.jdbc.geometry.binary.BinaryWriter; | |
34 | import net.postgis.jdbc.geometry.binary.ValueSetter; | |
35 | import net.postgis.tools.testutils.TestContainerController; | |
36 | import net.postgis.jdbc.geometry.util.VersionUtil; | |
37 | import org.slf4j.Logger; | |
38 | import org.slf4j.LoggerFactory; | |
39 | import org.testng.Assert; | |
40 | import org.testng.ITestContext; | |
41 | import org.testng.annotations.AfterClass; | |
42 | import org.testng.annotations.BeforeClass; | |
43 | import org.testng.annotations.Test; | |
44 | ||
45 | import java.sql.Connection; | |
46 | import java.sql.DriverManager; | |
47 | import java.sql.PreparedStatement; | |
48 | import java.sql.ResultSet; | |
49 | import java.sql.SQLException; | |
50 | import java.sql.Statement; | |
51 | import java.sql.Types; | |
52 | import java.util.Objects; | |
53 | ||
54 | ||
55 | public class ParserTest { | |
56 | ||
57 | private static final Logger logger = LoggerFactory.getLogger(ParserTest.class); | |
58 | ||
59 | private static final String DRIVER_WRAPPER_CLASS_NAME = "net.postgis.jdbc.DriverWrapper"; | |
60 | ||
61 | private static final String DRIVER_WRAPPER_AUTOPROBE_CLASS_NAME = "net.postgis.jdbc.DriverWrapperAutoprobe"; | |
62 | ||
63 | /** The srid we use for the srid tests */ | |
64 | public static final int SRID = 4326; | |
65 | ||
66 | /** The string prefix we get for the srid tests */ | |
67 | public static final String SRIDPREFIX = "SRID=" + SRID + ";"; | |
68 | ||
69 | /** | |
70 | * Our set of geometries to test. | |
71 | */ | |
72 | public static final String ALL = "ALL"; | |
73 | public static final String ONLY10 = "ONLY10"; | |
74 | public static final String EQUAL10 = "EQUAL10"; | |
75 | public static final String[][] testset = new String[][]{ | |
76 | { | |
77 | ALL, // 2D | |
78 | "POINT(10 10)"}, | |
79 | { | |
80 | ALL, // 3D with 3rd coordinate set to 0 | |
81 | "POINT(10 10 0)"}, | |
82 | { | |
83 | ALL, // 3D | |
84 | "POINT(10 10 20)"}, | |
85 | { | |
86 | ALL, // 3D with scientific notation | |
87 | "POINT(1e100 1.2345e-100 -2e-5)"}, | |
88 | { | |
89 | ONLY10, // 2D + Measures | |
90 | "POINTM(10 10 20)"}, | |
91 | { | |
92 | ONLY10, // 3D + Measures | |
93 | "POINT(10 10 20 30)"}, | |
94 | { | |
95 | ALL, // broken format, see http://lists.jump-project.org/pipermail/jts-devel/2006-April/001572.html | |
96 | "MULTIPOINT(11 12, 20 20)"}, | |
97 | { | |
98 | ALL,// broken format | |
99 | "MULTIPOINT(11 12 13, 20 20 20)"}, | |
100 | { | |
101 | ONLY10,// broken format | |
102 | "MULTIPOINTM(11 12 13, 20 20 20)"}, | |
103 | { | |
104 | ONLY10,// broken format | |
105 | "MULTIPOINT(11 12 13 14,20 20 20 20)"}, | |
106 | { | |
107 | ALL, // OGC conforming format | |
108 | "MULTIPOINT((11 12), (20 20))"}, | |
109 | { | |
110 | ALL, | |
111 | "MULTIPOINT((11 12 13), (20 20 20))"}, | |
112 | { | |
113 | ONLY10, | |
114 | "MULTIPOINTM((11 12 13), (20 20 20))"}, | |
115 | { | |
116 | ONLY10, | |
117 | "MULTIPOINT((11 12 13 14),(20 20 20 20))"}, | |
118 | { | |
119 | ALL, | |
120 | "LINESTRING(10 10,20 20,50 50,34 34)"}, | |
121 | { | |
122 | ALL, | |
123 | "LINESTRING(10 10 20,20 20 20,50 50 50,34 34 34)"}, | |
124 | { | |
125 | ONLY10, | |
126 | "LINESTRINGM(10 10 20,20 20 20,50 50 50,34 34 34)"}, | |
127 | { | |
128 | ONLY10, | |
129 | "LINESTRING(10 10 20 20,20 20 20 20,50 50 50 50,34 34 34 50)"}, | |
130 | { | |
131 | ALL, | |
132 | "POLYGON((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))"}, | |
133 | { | |
134 | ALL, | |
135 | "POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"}, | |
136 | { | |
137 | ONLY10, | |
138 | "POLYGONM((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"}, | |
139 | { | |
140 | ONLY10, | |
141 | "POLYGON((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7))"}, | |
142 | { | |
143 | ALL, | |
144 | "MULTIPOLYGON(((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)),((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)))"}, | |
145 | { | |
146 | ALL, | |
147 | "MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
148 | { | |
149 | ONLY10, | |
150 | "MULTIPOLYGONM(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
151 | { | |
152 | ONLY10, | |
153 | "MULTIPOLYGON(((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7)),((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7)))"}, | |
154 | { | |
155 | ALL, | |
156 | "MULTILINESTRING((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))"}, | |
157 | { | |
158 | ALL, | |
159 | "MULTILINESTRING((10 10 5,20 10 5,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"}, | |
160 | { | |
161 | ONLY10, | |
162 | "MULTILINESTRINGM((10 10 7,20 10 7,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"}, | |
163 | { | |
164 | ONLY10, | |
165 | "MULTILINESTRING((10 10 0 7,20 10 0 7,20 20 0 7,20 10 0 7,10 10 0 7),(5 5 0 7,5 6 0 7,6 6 0 7,6 5 0 7,5 5 0 7))"}, | |
166 | { | |
167 | ALL, | |
168 | "GEOMETRYCOLLECTION(POINT(10 10),POINT(20 20))"}, | |
169 | { | |
170 | ALL, | |
171 | "GEOMETRYCOLLECTION(POINT(10 10 20),POINT(20 20 20))"}, | |
172 | { | |
173 | ONLY10, | |
174 | "GEOMETRYCOLLECTION(POINT(10 10 20 7),POINT(20 20 20 7))"}, | |
175 | { | |
176 | ALL, | |
177 | "GEOMETRYCOLLECTION(LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34))"}, | |
178 | { | |
179 | ALL, | |
180 | "GEOMETRYCOLLECTION(POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
181 | { | |
182 | ONLY10, // Cannot be parsed by 0.X servers, broken format | |
183 | "GEOMETRYCOLLECTION(MULTIPOINT(10 10 10, 20 20 20),MULTIPOINT(10 10 10, 20 20 20))"}, | |
184 | { | |
185 | ONLY10, // Cannot be parsed by 0.X servers, OGC conformant | |
186 | "GEOMETRYCOLLECTION(MULTIPOINT((10 10 10), (20 20 20)),MULTIPOINT((10 10 10), (20 20 20)))"}, | |
187 | { | |
188 | EQUAL10, // PostGIs 0.X "flattens" this geometry, so it is not | |
189 | // equal after reparsing. | |
190 | "GEOMETRYCOLLECTION(MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
191 | { | |
192 | EQUAL10,// PostGIs 0.X "flattens" this geometry, so it is not equal | |
193 | // after reparsing. | |
194 | "GEOMETRYCOLLECTION(MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))))"}, | |
195 | { | |
196 | ALL, | |
197 | "GEOMETRYCOLLECTION(POINT(10 10 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
198 | { | |
199 | ONLY10, // Collections that contain both X and MultiX do not work on | |
200 | // PostGIS 0.x, broken format | |
201 | "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT(10 10 10, 20 20 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
202 | { | |
203 | ONLY10, // Collections that contain both X and MultiX do not work on | |
204 | // PostGIS 0.x, OGC conformant | |
205 | "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT((10 10 10), (20 20 20)),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"}, | |
206 | { | |
207 | ALL,// new (correct) representation | |
208 | "GEOMETRYCOLLECTION EMPTY"}, | |
209 | { | |
210 | ALL, | |
211 | "GEOMETRYCOLLECTIONM(POINTM(10 10 20),POINTM(20 20 20))"}, | |
212 | // end | |
213 | }; | |
214 | ||
215 | public static final String[][] testSetNonWorking = new String[][]{ | |
216 | { | |
217 | ALL, // Old (bad) PostGIS 0.X Representation | |
218 | "GEOMETRYCOLLECTION(EMPTY)"}, | |
219 | { | |
220 | ONLY10,// new (correct) representation - does not work on 0.X | |
221 | "POINT EMPTY"}, | |
222 | { | |
223 | ONLY10,// new (correct) representation - does not work on 0.X | |
224 | "LINESTRING EMPTY"}, | |
225 | { | |
226 | ONLY10,// new (correct) representation - does not work on 0.X | |
227 | "POLYGON EMPTY"}, | |
228 | { | |
229 | ONLY10,// new (correct) representation - does not work on 0.X | |
230 | "MULTIPOINT EMPTY"}, | |
231 | { | |
232 | ONLY10,// new (correct) representation - does not work on 0.X | |
233 | "MULTILINESTRING EMPTY"}, | |
234 | { | |
235 | ONLY10,// new (correct) representation - does not work on 0.X | |
236 | "MULTIPOLYGON EMPTY"} | |
237 | }; | |
238 | ||
239 | private static BinaryParser binaryParser = new BinaryParser(); | |
240 | ||
241 | private static final BinaryWriter binaryWriter = new BinaryWriter(); | |
242 | ||
243 | private Connection connection = null; | |
244 | ||
245 | private Statement statement = null; | |
246 | ||
247 | ||
248 | @Test | |
249 | public void testParser() throws Exception { | |
250 | for (String[] aTestset : testset) { | |
251 | test(aTestset[1], aTestset[0]); | |
252 | test(SRIDPREFIX + aTestset[1], aTestset[0]); | |
253 | } | |
254 | } | |
255 | ||
256 | ||
257 | public void test(String WKT, String flags) throws SQLException { | |
258 | logger.debug("Original: {} ", WKT); | |
259 | Geometry geom = GeometryBuilder.geomFromString(WKT); | |
260 | String parsed = geom.toString(); | |
261 | logger.debug("Parsed: {}", parsed); | |
262 | Geometry regeom = GeometryBuilder.geomFromString(parsed); | |
263 | String reparsed = regeom.toString(); | |
264 | logger.debug("Re-Parsed: {}", reparsed); | |
265 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
266 | Assert.assertEquals(reparsed, parsed, "Text Reps are not equal"); | |
267 | ||
268 | String hexNWKT = binaryWriter.writeHexed(regeom, ValueSetter.NDR.NUMBER); | |
269 | logger.debug("NDRHex: {}", hexNWKT); | |
270 | regeom = GeometryBuilder.geomFromString(hexNWKT); | |
271 | logger.debug("ReNDRHex: {}", regeom); | |
272 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
273 | ||
274 | String hexXWKT = binaryWriter.writeHexed(regeom, ValueSetter.XDR.NUMBER); | |
275 | logger.debug("XDRHex: {}", hexXWKT); | |
276 | regeom = GeometryBuilder.geomFromString(hexXWKT); | |
277 | logger.debug("ReXDRHex: {}", regeom); | |
278 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
279 | ||
280 | byte[] NWKT = binaryWriter.writeBinary(regeom, ValueSetter.NDR.NUMBER); | |
281 | regeom = binaryParser.parse(NWKT); | |
282 | logger.debug("NDR: {}", regeom); | |
283 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
284 | ||
285 | byte[] XWKT = binaryWriter.writeBinary(regeom, ValueSetter.XDR.NUMBER); | |
286 | regeom = binaryParser.parse(XWKT); | |
287 | logger.debug("XDR: {}", regeom); | |
288 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
289 | ||
290 | final String postGISVersionString = VersionUtil.retrievePostGISServerVersionString(connection); | |
291 | logger.debug("postGISVersionString: {}", postGISVersionString); | |
292 | final String postGISMajorVersion = VersionUtil.retrievePostGISServerMajorVersion(connection); | |
293 | logger.debug("postGISMajorVersion: {}", postGISMajorVersion); | |
294 | final String postGISMinorVersion = VersionUtil.retrievePostGISServerMinorVersion(connection); | |
295 | logger.debug("postGISMinorVersion: {}", postGISMinorVersion); | |
296 | ||
297 | int serverPostgisMajor = 0; | |
298 | try { | |
299 | serverPostgisMajor = Integer.parseInt(postGISMajorVersion); | |
300 | } catch (NumberFormatException nfe) { | |
301 | logger.error("Caught a number format exception attempting to parse PostGIS Server Major Version"); | |
302 | } | |
303 | ||
304 | if ((Objects.equals(flags, ONLY10)) && serverPostgisMajor < 1) { | |
305 | logger.info("PostGIS server too old, skipping test on database connection {}", connection.getCatalog()); | |
306 | } else { | |
307 | logger.debug("Testing on connection {}", connection.getCatalog()); | |
308 | ||
309 | Geometry sqlGeom = viaSQL(WKT); | |
310 | logger.debug("SQLin: {}", sqlGeom); | |
311 | if (!geom.equals(sqlGeom)) { | |
312 | logger.warn("Geometries after SQL are not equal"); | |
313 | if (Objects.equals(flags, EQUAL10) && serverPostgisMajor < 1) { | |
314 | logger.info("This is expected with PostGIS {}.X", serverPostgisMajor); | |
315 | } else { | |
316 | Assert.fail(); | |
317 | } | |
318 | } | |
319 | ||
320 | Geometry sqlreGeom = viaSQL(parsed); | |
321 | logger.debug("SQLout: {}", sqlreGeom); | |
322 | if (!geom.equals(sqlreGeom)) { | |
323 | logger.warn("Reparsed Geometries after SQL are not equal!"); | |
324 | if (Objects.equals(flags, EQUAL10) && serverPostgisMajor < 1) { | |
325 | logger.info("This is expected with PostGIS {}.X", serverPostgisMajor); | |
326 | } else { | |
327 | Assert.fail(); | |
328 | } | |
329 | } | |
330 | ||
331 | sqlreGeom = viaPrepSQL(geom, connection); | |
332 | logger.debug("Prepared: {}", sqlreGeom.toString()); | |
333 | if (!geom.equals(sqlreGeom)) { | |
334 | logger.warn("Reparsed Geometries after prepared StatementSQL are not equal!"); | |
335 | if (Objects.equals(flags, EQUAL10) && serverPostgisMajor < 1) { | |
336 | logger.info("This is expected with PostGIS {}.X", serverPostgisMajor); | |
337 | } else { | |
338 | Assert.fail(); | |
339 | } | |
340 | } | |
341 | ||
342 | /* | |
343 | // Temporarily removing this check since it breaks between PostGIS v2.4.4 and PostGIS v2.5.0 | |
344 | // Tests performed via psql between mdillon/postgis:9.3 and mdillon/postgis:9.4 shows the breakage | |
345 | // Test is also broken in mdillon/postgis:11-alpine | |
346 | // In psql, the sql statement "SELECT ST_AsEWKT(geometry_in('POINT(1e100 1.2345e-100 -2e-5)'));" returns | |
347 | // "POINT(1e+100 1.2345e-100 -2e-05)" with 9.3 and "POINT(1e+100 0 -0.00002)" with 9.4 and later | |
348 | ||
349 | // asEWKT() function is not present on PostGIS 0.X, and the test | |
350 | // is pointless as 0.X uses EWKT as canonical rep so the same | |
351 | // functionality was already tested above. | |
352 | if (serverPostgisMajor >= 1) { | |
353 | sqlGeom = ewktViaSQL(WKT, statement); | |
354 | logger.debug("asEWKT: {}", sqlGeom); | |
355 | Assert.assertEquals(geom, sqlGeom); | |
356 | } | |
357 | */ | |
358 | ||
359 | // asEWKB() function is not present on PostGIS 0.X. | |
360 | if (serverPostgisMajor >= 1) { | |
361 | sqlGeom = ewkbViaSQL(WKT, statement); | |
362 | logger.debug("asEWKB: {}", sqlGeom); | |
363 | Assert.assertEquals(geom, sqlGeom); | |
364 | } | |
365 | ||
366 | // HexEWKB parsing is not present on PostGIS 0.X. | |
367 | if (serverPostgisMajor >= 1) { | |
368 | sqlGeom = viaSQL(hexNWKT); | |
369 | logger.debug("hexNWKT: {}", sqlGeom); | |
370 | Assert.assertEquals(geom, sqlGeom); | |
371 | } | |
372 | ||
373 | if (serverPostgisMajor >= 1) { | |
374 | sqlGeom = viaSQL(hexXWKT); | |
375 | logger.debug("hexXWKT: {}", sqlGeom); | |
376 | Assert.assertEquals(geom, sqlGeom); | |
377 | } | |
378 | ||
379 | // Canonical binary input is not present before 1.0 | |
380 | if (serverPostgisMajor >= 1) { | |
381 | sqlGeom = binaryViaSQL(NWKT, connection); | |
382 | logger.debug("NWKT: {}", sqlGeom); | |
383 | Assert.assertEquals(geom, sqlGeom); | |
384 | } | |
385 | ||
386 | if (serverPostgisMajor >= 1) { | |
387 | sqlGeom = binaryViaSQL(XWKT, connection); | |
388 | logger.debug("XWKT: {}", sqlGeom); | |
389 | Assert.assertEquals(geom, sqlGeom); | |
390 | } | |
391 | } | |
392 | } | |
393 | ||
394 | ||
395 | /** Pass a geometry representation through the SQL server */ | |
396 | private Geometry viaSQL(String rep) throws SQLException { | |
397 | logger.trace("Geometry viaSQL(String rep)"); | |
398 | logger.trace("[P] rep => {}", rep); | |
399 | ResultSet resultSet = statement.executeQuery("SELECT geometry_in('" + rep + "')"); | |
400 | resultSet.next(); | |
401 | return ((PGgeometry) resultSet.getObject(1)).getGeometry(); | |
402 | } | |
403 | ||
404 | ||
405 | /** | |
406 | * Pass a geometry representation through the SQL server via prepared | |
407 | * statement | |
408 | */ | |
409 | private static Geometry viaPrepSQL(Geometry geom, Connection conn) throws SQLException { | |
410 | PreparedStatement preparedStatement = conn.prepareStatement("SELECT ?::geometry"); | |
411 | PGgeometry wrapper = new PGgeometry(geom); | |
412 | preparedStatement.setObject(1, wrapper, Types.OTHER); | |
413 | ResultSet resultSet = preparedStatement.executeQuery(); | |
414 | resultSet.next(); | |
415 | PGgeometry resultwrapper = (PGgeometry)resultSet.getObject(1); | |
416 | return resultwrapper.getGeometry(); | |
417 | } | |
418 | ||
419 | ||
420 | /** Pass a geometry representation through the SQL server via EWKT */ | |
421 | private static Geometry ewktViaSQL(String rep, Statement stat) throws SQLException { | |
422 | ResultSet resultSet = stat.executeQuery("SELECT ST_AsEWKT(geometry_in('" + rep + "'))"); | |
423 | resultSet.next(); | |
424 | String resrep = resultSet.getString(1); | |
425 | return GeometryBuilder.geomFromString(resrep); | |
426 | } | |
427 | ||
428 | ||
429 | /** Pass a geometry representation through the SQL server via EWKB */ | |
430 | private static Geometry ewkbViaSQL(String rep, Statement stat) throws SQLException { | |
431 | ResultSet resultSet = stat.executeQuery("SELECT ST_AsEWKB(geometry_in('" + rep + "'))"); | |
432 | resultSet.next(); | |
433 | byte[] resrep = resultSet.getBytes(1); | |
434 | return binaryParser.parse(resrep); | |
435 | } | |
436 | ||
437 | ||
438 | /** Pass a EWKB geometry representation through the server */ | |
439 | private static Geometry binaryViaSQL(byte[] rep, Connection conn) throws SQLException { | |
440 | PreparedStatement preparedStatement = conn.prepareStatement("SELECT ?::bytea::geometry"); | |
441 | preparedStatement.setBytes(1, rep); | |
442 | ResultSet resultSet = preparedStatement.executeQuery(); | |
443 | resultSet.next(); | |
444 | PGgeometry resultwrapper = ((PGgeometry) resultSet.getObject(1)); | |
445 | return resultwrapper.getGeometry(); | |
446 | } | |
447 | ||
448 | ||
449 | @BeforeClass | |
450 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
451 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
452 | Assert.assertNotNull(jdbcUrlSuffix); | |
453 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
454 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
455 | Assert.assertNotNull(jdbcUsername); | |
456 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
457 | Assert.assertNotNull(jdbcPassword); | |
458 | Class.forName(DRIVER_WRAPPER_CLASS_NAME); | |
459 | Class.forName(DRIVER_WRAPPER_AUTOPROBE_CLASS_NAME); | |
460 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
461 | statement = connection.createStatement(); | |
462 | } | |
463 | ||
464 | ||
465 | @AfterClass | |
466 | public void unallocateDatabaseResources() throws Exception { | |
467 | if ((statement != null) && (!statement.isClosed())) { | |
468 | statement.close(); | |
469 | } | |
470 | if ((connection != null) && (!connection.isClosed())) { | |
471 | connection.close(); | |
472 | } | |
473 | } | |
474 | ||
475 | ||
476 | }⏎ |
0 | /* | |
1 | * ServerTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2017 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc; | |
28 | ||
29 | ||
30 | import org.testng.Assert; | |
31 | import org.testng.annotations.Test; | |
32 | ||
33 | import java.io.ByteArrayOutputStream; | |
34 | import java.io.NotSerializableException; | |
35 | import java.io.ObjectOutputStream; | |
36 | ||
37 | ||
38 | public class SerializationTest { | |
39 | ||
40 | ||
41 | @Test | |
42 | public void serializationCheckPGgeometry() throws Exception { | |
43 | try { | |
44 | new ObjectOutputStream(new ByteArrayOutputStream()) | |
45 | .writeObject(new PGgeometry("MULTIPOLYGON(((1 1,1 2,2 1,1 1)))")); | |
46 | } | |
47 | catch (NotSerializableException ex) { | |
48 | Assert.fail("serialization of PGgeometry failed: " + ex); | |
49 | } | |
50 | } | |
51 | ||
52 | ||
53 | } |
0 | /* | |
1 | * ServerTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc; | |
28 | ||
29 | ||
30 | import net.postgis.tools.testutils.TestContainerController; | |
31 | import org.slf4j.Logger; | |
32 | import org.slf4j.LoggerFactory; | |
33 | import org.testng.Assert; | |
34 | import org.testng.ITestContext; | |
35 | import org.testng.annotations.AfterClass; | |
36 | import org.testng.annotations.BeforeClass; | |
37 | import org.testng.annotations.Test; | |
38 | ||
39 | import java.sql.*; | |
40 | import java.util.UUID; | |
41 | ||
42 | ||
43 | public class ServerTest { | |
44 | ||
45 | private static final Logger logger = LoggerFactory.getLogger(ServerTest.class); | |
46 | ||
47 | private static final String JDBC_DRIVER_CLASS_NAME = "org.postgresql.Driver"; | |
48 | ||
49 | private static final String DATABASE_TABLE_NAME_PREFIX = "jdbc_test"; | |
50 | ||
51 | private Connection connection = null; | |
52 | ||
53 | private Statement statement = null; | |
54 | ||
55 | ||
56 | @Test | |
57 | public void testServer() throws Exception { | |
58 | String dbtable = DATABASE_TABLE_NAME_PREFIX + "_" + UUID.randomUUID().toString().replaceAll("-", ""); | |
59 | ||
60 | String dropSQL = "drop table " + dbtable; | |
61 | String createSQL = "create table " + dbtable + " (geom geometry, id int4)"; | |
62 | String insertPointSQL = "insert into " + dbtable + " values ('POINT (10 10 10)',1)"; | |
63 | String insertPolygonSQL = "insert into " + dbtable + " values ('POLYGON ((0 0 0,0 10 0,10 10 0,10 0 0,0 0 0))',2)"; | |
64 | ||
65 | logger.debug("Adding geometric type entries..."); | |
66 | ((org.postgresql.PGConnection)connection).addDataType("geometry", PGgeometry.class); | |
67 | ((org.postgresql.PGConnection)connection).addDataType("box3d", PGbox3d.class); | |
68 | ||
69 | logger.debug("Creating table with geometric types..."); | |
70 | boolean tableExists = false; | |
71 | DatabaseMetaData databaseMetaData = connection.getMetaData(); | |
72 | try (ResultSet resultSet = databaseMetaData.getTables(null, null, dbtable.toLowerCase(), new String[] {"TABLE"})) { | |
73 | while (resultSet.next()) { | |
74 | tableExists = true; | |
75 | } | |
76 | } | |
77 | if (tableExists) { | |
78 | statement.execute(dropSQL); | |
79 | } | |
80 | statement.execute(createSQL); | |
81 | ||
82 | logger.debug("Inserting point..."); | |
83 | statement.execute(insertPointSQL); | |
84 | ||
85 | logger.debug("Inserting polygon..."); | |
86 | statement.execute(insertPolygonSQL); | |
87 | ||
88 | logger.debug("Querying table..."); | |
89 | ResultSet resultSet = statement.executeQuery("select ST_AsText(geom),id from " + dbtable); | |
90 | while (resultSet.next()) { | |
91 | Object obj = resultSet.getObject(1); | |
92 | int id = resultSet.getInt(2); | |
93 | logger.debug("Row {}: {}", id, obj.toString()); | |
94 | } | |
95 | ||
96 | } | |
97 | ||
98 | ||
99 | @BeforeClass | |
100 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
101 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
102 | Assert.assertNotNull(jdbcUrlSuffix); | |
103 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
104 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
105 | Assert.assertNotNull(jdbcUsername); | |
106 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
107 | Assert.assertNotNull(jdbcPassword); | |
108 | Class.forName(JDBC_DRIVER_CLASS_NAME); | |
109 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
110 | statement = connection.createStatement(); | |
111 | } | |
112 | ||
113 | ||
114 | @AfterClass | |
115 | public void unallocateDatabaseResources() throws Exception { | |
116 | if ((statement != null) && (!statement.isClosed())) { | |
117 | statement.close(); | |
118 | } | |
119 | if ((connection != null) && (!connection.isClosed())) { | |
120 | connection.close(); | |
121 | } | |
122 | } | |
123 | ||
124 | ||
125 | }⏎ |
0 | package net.postgis.jdbc; | |
1 | ||
2 | import org.junit.Assert; | |
3 | import org.junit.Test; | |
4 | ||
5 | import java.sql.Driver; | |
6 | import java.sql.DriverManager; | |
7 | import java.sql.SQLException; | |
8 | ||
9 | /** | |
10 | * Tests to ensure that the drivers that are registered as services in META-INF/services/java.sql.Driver are resolved | |
11 | * correctly. | |
12 | */ | |
13 | public class ServiceTest { | |
14 | ||
15 | @Test | |
16 | public void testWrapperService() throws SQLException { | |
17 | Driver driver = DriverManager.getDriver("jdbc:postgresql_postGIS:/"); | |
18 | Assert.assertEquals(DriverWrapper.class, driver.getClass()); | |
19 | } | |
20 | ||
21 | @Test | |
22 | public void testWrapperAutoprobeService() throws SQLException { | |
23 | Driver driver = DriverManager.getDriver("jdbc:postgresql_autogis:/"); | |
24 | Assert.assertEquals(DriverWrapperAutoprobe.class, driver.getClass()); | |
25 | } | |
26 | ||
27 | @Test | |
28 | public void testWrapperLWService() throws SQLException { | |
29 | Driver driver = DriverManager.getDriver("jdbc:postgresql_lwgis:/"); | |
30 | Assert.assertEquals(DriverWrapperLW.class, driver.getClass()); | |
31 | } | |
32 | ||
33 | } |
0 | /* | |
1 | * VersionPrinter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package net.postgis.jdbc; | |
26 | ||
27 | ||
28 | import net.postgis.tools.testutils.TestContainerController; | |
29 | import org.postgresql.Driver; | |
30 | import org.slf4j.Logger; | |
31 | import org.slf4j.LoggerFactory; | |
32 | import org.testng.Assert; | |
33 | import org.testng.ITestContext; | |
34 | import org.testng.annotations.AfterClass; | |
35 | import org.testng.annotations.BeforeClass; | |
36 | import org.testng.annotations.Test; | |
37 | ||
38 | import java.sql.*; | |
39 | ||
40 | ||
41 | /** | |
42 | * Prints out as much version information as available. | |
43 | */ | |
44 | public class VersionPrinter { | |
45 | ||
46 | private static final Logger logger = LoggerFactory.getLogger(VersionPrinter.class); | |
47 | ||
48 | private static final String JDBC_DRIVER_CLASS_NAME = "org.postgresql.Driver"; | |
49 | ||
50 | public static String[] POSTGIS_FUNCTIONS = { | |
51 | "postgis_version", | |
52 | "postgis_proj_version", | |
53 | "postgis_scripts_installed", | |
54 | "postgis_lib_version", | |
55 | "postgis_scripts_released", | |
56 | "postgis_uses_stats", | |
57 | "postgis_geos_version", | |
58 | "postgis_scripts_build_date", | |
59 | "postgis_lib_build_date", | |
60 | "postgis_full_version", | |
61 | "postgis_gdal_version", | |
62 | "postgis_libjson_version", | |
63 | "postgis_libxml_version", | |
64 | "postgis_raster_lib_version", | |
65 | "postgis_svn_version" | |
66 | }; | |
67 | ||
68 | private Connection connection = null; | |
69 | ||
70 | private Statement statement = null; | |
71 | ||
72 | ||
73 | @Test | |
74 | public void test() throws Exception { | |
75 | ||
76 | // Print PostGIS version | |
77 | logger.info("*** PostGIS jdbc client code ***"); | |
78 | String fullVersion = Version.getFullVersion(); | |
79 | Assert.assertNotNull(fullVersion); | |
80 | logger.info("\t getFullVersion: {}", fullVersion); | |
81 | ||
82 | // Print PostgreSQL JDBC Versions | |
83 | logger.info("*** PostgreSQL JDBC Driver ***"); | |
84 | String driverVersion = Driver.getVersion(); | |
85 | Assert.assertNotNull(driverVersion); | |
86 | logger.info("\t getVersion: {}", driverVersion); | |
87 | ||
88 | try { | |
89 | Driver driver = new Driver(); | |
90 | int majorVersion = driver.getMajorVersion(); | |
91 | Assert.assertNotEquals(majorVersion, 0); | |
92 | logger.info("\t getMajorVersion: {}", majorVersion); | |
93 | int minorVersion = driver.getMinorVersion(); | |
94 | Assert.assertNotEquals(minorVersion, 0); | |
95 | logger.info("\t getMinorVersion: {}", majorVersion); | |
96 | } catch (Exception e) { | |
97 | logger.error("Cannot create Driver instance: {}", e.getMessage()); | |
98 | } | |
99 | ||
100 | // Print PostgreSQL server versions | |
101 | Assert.assertNotNull(connection); | |
102 | Statement statement = connection.createStatement(); | |
103 | if (statement == null) { | |
104 | logger.info("No online version available."); | |
105 | } else { | |
106 | logger.info("*** PostgreSQL Server ***"); | |
107 | String versionString = getVersionString("version"); | |
108 | logger.debug("\t version: {}", versionString); | |
109 | ||
110 | // Print PostGIS versions | |
111 | logger.info("*** PostGIS Server ***"); | |
112 | for (String GISVERSION : POSTGIS_FUNCTIONS) { | |
113 | versionString = getVersionString(GISVERSION); | |
114 | logger.debug("\t {} version: {}", GISVERSION, versionString); | |
115 | } | |
116 | } | |
117 | } | |
118 | ||
119 | ||
120 | public String getVersionString(String function) throws SQLException { | |
121 | String result = "-- unavailable -- "; | |
122 | try { | |
123 | ResultSet resultSet = statement.executeQuery("SELECT " + function + "()"); | |
124 | if (resultSet.next()) { | |
125 | String version = resultSet.getString(1); | |
126 | if (version != null) { | |
127 | result = version.trim(); | |
128 | } else { | |
129 | result = "-- null result --"; | |
130 | } | |
131 | } else { | |
132 | result = "-- no result --"; | |
133 | } | |
134 | } catch (SQLException sqle) { | |
135 | // If the function does not exist, a SQLException will be thrown, but it should be caught an swallowed if | |
136 | // the "does not exist" string is in the error message. The SQLException might be thrown for some other | |
137 | // problem not related to the missing function, so rethrow it if it doesn't contain the string. | |
138 | if (!sqle.getMessage().contains("does not exist")) { | |
139 | throw sqle; | |
140 | } | |
141 | } | |
142 | return result; | |
143 | } | |
144 | ||
145 | ||
146 | @BeforeClass | |
147 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
148 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
149 | Assert.assertNotNull(jdbcUrlSuffix); | |
150 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
151 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
152 | Assert.assertNotNull(jdbcUsername); | |
153 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
154 | Assert.assertNotNull(jdbcPassword); | |
155 | Class.forName(JDBC_DRIVER_CLASS_NAME); | |
156 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
157 | statement = connection.createStatement(); | |
158 | } | |
159 | ||
160 | ||
161 | @AfterClass | |
162 | public void unallocateDatabaseResources() throws Exception { | |
163 | if ((statement != null) && (!statement.isClosed())) { | |
164 | statement.close(); | |
165 | } | |
166 | if ((connection != null) && (!connection.isClosed())) { | |
167 | connection.close(); | |
168 | } | |
169 | } | |
170 | ||
171 | ||
172 | }⏎ |
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2018 Phillip Ross, phillip.w.g.ross@gmail.com | |
16 | */ | |
17 | ||
18 | package net.postgis.jdbc.util; | |
19 | ||
20 | ||
21 | import net.postgis.tools.testutils.TestContainerController; | |
22 | import net.postgis.jdbc.geometry.util.VersionFunctions; | |
23 | import net.postgis.jdbc.geometry.util.VersionUtil; | |
24 | import org.slf4j.Logger; | |
25 | import org.slf4j.LoggerFactory; | |
26 | import org.testng.Assert; | |
27 | import org.testng.ITestContext; | |
28 | import org.testng.annotations.AfterMethod; | |
29 | import org.testng.annotations.BeforeMethod; | |
30 | import org.testng.annotations.Test; | |
31 | ||
32 | import java.sql.Connection; | |
33 | import java.sql.DriverManager; | |
34 | import java.sql.SQLException; | |
35 | import java.util.StringTokenizer; | |
36 | ||
37 | ||
38 | /** | |
39 | * Integration tests for VersionUtil. | |
40 | * | |
41 | * @author Phillip Ross | |
42 | */ | |
43 | public class VersionUtilIT { | |
44 | ||
45 | /** The static logger instance. */ | |
46 | private static final Logger logger = LoggerFactory.getLogger(VersionUtilIT.class); | |
47 | ||
48 | /** The jdbc url prefix containing the jdbc protocol to be used for tests. */ | |
49 | private static final String JDBC_URL_PROTOCOL_PREFIX = "jdbc:postgresql"; | |
50 | ||
51 | /** The JDBC Connection to be used for tests. */ | |
52 | private Connection connection = null; | |
53 | ||
54 | ||
55 | /** | |
56 | * Initializes a new JDBC Connection. | |
57 | * | |
58 | * @param ctx the test context | |
59 | * @throws Exception when an exception occurs | |
60 | */ | |
61 | @BeforeMethod | |
62 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
63 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
64 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
65 | Assert.assertNotNull(jdbcUrlSuffix); | |
66 | final String jdbcUrl = JDBC_URL_PROTOCOL_PREFIX + jdbcUrlSuffix; | |
67 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
68 | Assert.assertNotNull(jdbcUsername); | |
69 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
70 | Assert.assertNotNull(jdbcPassword); | |
71 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
72 | } | |
73 | ||
74 | ||
75 | /** | |
76 | * Un-allocates the JDBC connection. | |
77 | * | |
78 | * @throws Exception when an exception occurs | |
79 | */ | |
80 | @AfterMethod | |
81 | public void unallocateDatabaseResources() throws Exception { | |
82 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
83 | if ((connection != null) && (!connection.isClosed())) { | |
84 | connection.close(); | |
85 | } | |
86 | } | |
87 | ||
88 | ||
89 | /** | |
90 | * Test getting version string with a null connection. | |
91 | * | |
92 | * @throws Exception when an exception occurs | |
93 | */ | |
94 | @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*null connection.*") | |
95 | public void test_VersionUtil_GetVersionString_NullConnection() throws Exception { | |
96 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
97 | VersionUtil.getVersionString(null, VersionFunctions.POSTGIS_FULL_VERSION.toString()); | |
98 | } | |
99 | ||
100 | ||
101 | /** | |
102 | * Test getting version string with an invalid connection. | |
103 | * | |
104 | * @throws Exception when an exception occurs | |
105 | */ | |
106 | @Test(expectedExceptions = SQLException.class, expectedExceptionsMessageRegExp = ".*connection.*not valid.*") | |
107 | public void test_VersionUtil_GetVersionString_InvalidConnection() throws Exception { | |
108 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
109 | connection.close(); | |
110 | VersionUtil.getVersionString(connection, VersionFunctions.POSTGIS_FULL_VERSION.toString()); | |
111 | } | |
112 | ||
113 | ||
114 | /** | |
115 | * Test getting version string with an invalid function name. | |
116 | * | |
117 | * @throws Exception when an exception occurs | |
118 | */ | |
119 | @Test( | |
120 | expectedExceptions = SQLException.class, | |
121 | expectedExceptionsMessageRegExp = ".*(?!" + VersionUtil.NONEXISTENT_FUNCTION_ERROR_MESSAGE_CONTENT + ")" | |
122 | ) | |
123 | public void test_VersionUtil_GetVersionString_InvalidFunctionName() throws Exception { | |
124 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
125 | VersionUtil.getVersionString(connection, "invalid.function.name"); | |
126 | } | |
127 | ||
128 | ||
129 | /** | |
130 | * Test getting version string with a null function. | |
131 | * | |
132 | * @throws Exception when an exception occurs | |
133 | */ | |
134 | @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*null function.*") | |
135 | public void test_VersionUtil_GetVersionString_NullFunction() throws Exception { | |
136 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
137 | VersionUtil.getVersionString(connection, null); | |
138 | } | |
139 | ||
140 | ||
141 | /** | |
142 | * Test getting version string of an unavailable function. | |
143 | * | |
144 | * @throws Exception when an exception occurs | |
145 | */ | |
146 | @Test | |
147 | public void test_VersionUtil_GetVersionString_Unavailable() throws Exception { | |
148 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
149 | Assert.assertTrue( | |
150 | VersionUtil.getVersionString(connection, "nonexistent") | |
151 | .contains("unavailable") | |
152 | ); | |
153 | } | |
154 | ||
155 | ||
156 | /** | |
157 | * Test getting version strings for all enumerated version functions. | |
158 | * | |
159 | * @throws Exception when an exception occurs | |
160 | */ | |
161 | @Test | |
162 | public void test_VersionUtil_GetVersionString_VersionFunctionsEnum() throws Exception { | |
163 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
164 | for (int i = 0; i < VersionFunctions.values().length; i++) { | |
165 | String function = VersionFunctions.values()[i].toString(); | |
166 | String version = VersionUtil.getVersionString(connection, function); | |
167 | logger.debug("function [{}] => version string [{}]", function, version); | |
168 | } | |
169 | } | |
170 | ||
171 | ||
172 | /** | |
173 | * Test getting the server version string with a null connection. | |
174 | * | |
175 | * @throws Exception when an exception occurs | |
176 | */ | |
177 | @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*null connection.*") | |
178 | public void test_VersionUtil_RetrievePostGISServerVersionString_NullConnection() throws Exception { | |
179 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
180 | VersionUtil.retrievePostGISServerVersionString(null); | |
181 | } | |
182 | ||
183 | ||
184 | /** | |
185 | * Test getting the server version string with an invalid connection. | |
186 | * | |
187 | * @throws Exception when an exception occurs | |
188 | */ | |
189 | @Test(expectedExceptions = SQLException.class, expectedExceptionsMessageRegExp = ".*connection.*not valid.*") | |
190 | public void test_VersionUtil_RetrievePostGISServerVersionString_InvalidConnection() throws Exception { | |
191 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
192 | connection.close(); | |
193 | VersionUtil.retrievePostGISServerVersionString(connection); | |
194 | } | |
195 | ||
196 | ||
197 | /** | |
198 | * Test getting the server version string. | |
199 | * | |
200 | * @throws Exception when an exception occurs | |
201 | */ | |
202 | @Test | |
203 | public void test_VersionUtil_RetrievePostGISServerVersionString() throws Exception { | |
204 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
205 | String postGISServerVersionString = VersionUtil.retrievePostGISServerVersionString(connection); | |
206 | Assert.assertNotNull(postGISServerVersionString); | |
207 | logger.debug("PostGIS server version string [{}]", postGISServerVersionString); | |
208 | } | |
209 | ||
210 | ||
211 | /** | |
212 | * Test getting the server version with a null connection. | |
213 | * | |
214 | * @throws Exception when an exception occurs | |
215 | */ | |
216 | @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*null connection.*") | |
217 | public void test_VersionUtil_RetrievePostGISServerVersion_NullConnection() throws Exception { | |
218 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
219 | VersionUtil.retrievePostGISServerVersion(null); | |
220 | } | |
221 | ||
222 | ||
223 | /** | |
224 | * Test getting the server version with an invalid connection. | |
225 | * | |
226 | * @throws Exception when an exception occurs | |
227 | */ | |
228 | @Test(expectedExceptions = SQLException.class, expectedExceptionsMessageRegExp = ".*connection.*not valid.*") | |
229 | public void test_VersionUtil_RetrievePostGISServerVersion_InvalidConnection() throws Exception { | |
230 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
231 | connection.close(); | |
232 | VersionUtil.retrievePostGISServerVersion(connection); | |
233 | } | |
234 | ||
235 | ||
236 | /** | |
237 | * Test getting the server version. | |
238 | * | |
239 | * @throws Exception when an exception occurs | |
240 | */ | |
241 | @Test | |
242 | public void test_VersionUtil_RetrievePostGISServerVersion() throws Exception { | |
243 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
244 | final String version = VersionUtil.retrievePostGISServerVersion(connection); | |
245 | Assert.assertNotNull(version); | |
246 | logger.debug("PostGIS server version [{}]", version); | |
247 | } | |
248 | ||
249 | ||
250 | /** | |
251 | * Test getting the server major version with a null connection. | |
252 | * | |
253 | * @throws Exception when an exception occurs | |
254 | */ | |
255 | @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*null connection.*") | |
256 | public void test_VersionUtil_RetrievePostGISServerMajorVersion_NullConnection() throws Exception { | |
257 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
258 | VersionUtil.retrievePostGISServerMajorVersion(null); | |
259 | } | |
260 | ||
261 | ||
262 | /** | |
263 | * Test getting the server major version with an invalid connection. | |
264 | * | |
265 | * @throws Exception when an exception occurs | |
266 | */ | |
267 | @Test(expectedExceptions = SQLException.class, expectedExceptionsMessageRegExp = ".*connection.*not valid.*") | |
268 | public void test_VersionUtil_RetrievePostGISServerMajorVersion_InvalidConnection() throws Exception { | |
269 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
270 | connection.close(); | |
271 | VersionUtil.retrievePostGISServerMajorVersion(connection); | |
272 | } | |
273 | ||
274 | ||
275 | /** | |
276 | * Test getting the server major version. | |
277 | * | |
278 | * @throws Exception when an exception occurs | |
279 | */ | |
280 | @Test | |
281 | public void test_VersionUtil_RetrievePostGISServerMajorVersion() throws Exception { | |
282 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
283 | final String version = VersionUtil.retrievePostGISServerMajorVersion(connection); | |
284 | Assert.assertNotNull(version); | |
285 | logger.debug("PostGIS server major version [{}]", version); | |
286 | } | |
287 | ||
288 | ||
289 | /** | |
290 | * Test getting the server minor version with a null connection. | |
291 | * | |
292 | * @throws Exception when an exception occurs | |
293 | */ | |
294 | @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*null connection.*") | |
295 | public void test_VersionUtil_RetrievePostGISServerMinorVersion_NullConnection() throws Exception { | |
296 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
297 | VersionUtil.retrievePostGISServerMinorVersion(null); | |
298 | } | |
299 | ||
300 | ||
301 | /** | |
302 | * Test getting the server minor version with an invalid connection. | |
303 | * | |
304 | * @throws Exception when an exception occurs | |
305 | */ | |
306 | @Test(expectedExceptions = SQLException.class, expectedExceptionsMessageRegExp = ".*connection.*not valid.*") | |
307 | public void test_VersionUtil_RetrievePostGISServerMinorVersion_InvalidConnection() throws Exception { | |
308 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
309 | connection.close(); | |
310 | VersionUtil.retrievePostGISServerMinorVersion(connection); | |
311 | } | |
312 | ||
313 | ||
314 | /** | |
315 | * Test getting the server minor version. | |
316 | * | |
317 | * @throws Exception when an exception occurs | |
318 | */ | |
319 | @Test | |
320 | public void test_VersionUtil_RetrievePostGISServerMinorVersion() throws Exception { | |
321 | logger.trace("[{}#{}]", getClass().getName(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
322 | final String version = VersionUtil.retrievePostGISServerMinorVersion(connection); | |
323 | Assert.assertNotNull(version); | |
324 | logger.debug("PostGIS server minor version [{}]", version); | |
325 | } | |
326 | ||
327 | ||
328 | /** | |
329 | * Test additional parsing assertions against retrieved versions. | |
330 | * | |
331 | * @throws Exception when an exception occurs | |
332 | */ | |
333 | @Test | |
334 | public void testServerVersionParsing() throws Exception { | |
335 | logger.trace("[{}.{}]", getClass(), new Object(){}.getClass().getEnclosingMethod().getName()); | |
336 | final String versionString = VersionUtil.retrievePostGISServerVersionString(connection); | |
337 | Assert.assertNotNull(versionString); | |
338 | final String versionFull = VersionUtil.retrievePostGISServerVersion(connection); | |
339 | Assert.assertNotNull(versionFull); | |
340 | Assert.assertTrue(versionString.startsWith(versionFull)); | |
341 | final StringTokenizer stringTokenizer = | |
342 | new StringTokenizer(versionString, VersionUtil.POSTGIS_SERVER_VERSION_SEPERATOR); | |
343 | Assert.assertTrue(stringTokenizer.countTokens() > 0); | |
344 | final String versionMajor = VersionUtil.retrievePostGISServerMajorVersion(connection); | |
345 | Assert.assertEquals(versionMajor, stringTokenizer.nextToken()); | |
346 | if (stringTokenizer.countTokens() > 1) { | |
347 | final String versionMinor = VersionUtil.retrievePostGISServerMinorVersion(connection); | |
348 | Assert.assertEquals(versionMinor, stringTokenizer.nextToken()); | |
349 | } | |
350 | } | |
351 | ||
352 | ||
353 | } |
0 | <configuration debug="false"> | |
1 | ||
2 | <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | |
3 | <layout class="ch.qos.logback.classic.PatternLayout"> | |
4 | <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> | |
5 | </layout> | |
6 | </appender> | |
7 | ||
8 | <root level="debug"> | |
9 | <appender-ref ref="STDOUT" /> | |
10 | </root> | |
11 | ||
12 | <logger name="com.github.dockerjava" level="ERROR"/> | |
13 | <logger name="org.testcontainers" level="ERROR"/> | |
14 | <logger name="net.postgis" level="ERROR"/> | |
15 | ||
16 | <logger name="net.postgis" level="ERROR"/> | |
17 | ||
18 | </configuration>⏎ |
0 | <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> | |
1 | <suite name="Postgis JDBC Extensions Test Suite" verbose="1"> | |
2 | ||
3 | <test name="Postgis JDBC Tests"> | |
4 | <classes> | |
5 | <class name="net.postgis.jdbc.DatatypesTest"/> | |
6 | <class name="net.postgis.jdbc.SerializationTest"/> | |
7 | </classes> | |
8 | </test> | |
9 | ||
10 | </suite> |
0 | <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> | |
1 | <suite name="Postgis JDBC Extensions Integration Test Suite" verbose="1"> | |
2 | ||
3 | <parameter name="test.container.image-name" value="${test.container.image}"/> | |
4 | <parameter name="test.container.port" value="${test.db.port}"/> | |
5 | <parameter name="test.container.env.user" value="${test.db.username}"/> | |
6 | <parameter name="test.container.env.password" value="${test.db.password}"/> | |
7 | <parameter name="test.container.env.db" value="${test.db.name}"/> | |
8 | ||
9 | <test name="Postgis JDBC Integration Tests"> | |
10 | <classes> | |
11 | <class name="net.postgis.tools.testutils.TestContainerController"/> | |
12 | <class name="net.postgis.jdbc.util.VersionUtilIT"/> | |
13 | <class name="net.postgis.jdbc.DatatypesAutoRegistrationTest"/> | |
14 | <class name="net.postgis.jdbc.BoxesTest"/> | |
15 | <class name="net.postgis.jdbc.EmptyGeometriesTest"/> | |
16 | <class name="net.postgis.jdbc.GeographyDatatypeTest"/> | |
17 | <class name="net.postgis.jdbc.ParserTest"/> | |
18 | <class name="net.postgis.jdbc.ServerTest"/> | |
19 | <class name="net.postgis.jdbc.VersionPrinter"/> | |
20 | </classes> | |
21 | </test> | |
22 | ||
23 | </suite> |
0 | Todo for PostGIS 1.0 compatible JDBC classes | |
1 | ||
2 | - even more Testing, especialy against different postgis, | |
3 | pgjdbc and postgresql releases. | |
4 | ||
5 | - Use JUnit for testing (maven) | |
6 | ||
7 | - Unify the build of app java projects -> maven | |
8 | ||
9 | - Handling of length() - esp. with modifying the geometries | |
10 | ||
11 | - Handling of hashCode() - esp. with modifying the geometries | |
12 | ||
13 | - Test correctness of toString() and getValue() for compatibility reasons | |
14 | ||
15 | - See where the code can be cleaned and leaned. | |
16 | ||
17 | - Finish JTS support | |
18 | ||
19 | - Creating a sane extension interface for pgjdbc that allows binary | |
20 | transfers and convince upstream to use it, then create support for it. | |
21 | ||
22 | - Possibly adding server side code to support plJava | |
23 | http://gborg.postgresql.org/project/pljava/projdisplay.php | |
24 | ||
25 | - Rework the BinaryParser/BinaryWriter to work on SQLInput/SQLOutput | |
26 | instances, as well as reworking ValueGetter/ValueSetter to implment those interfaces. |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
2 | <modelVersion>4.0.0</modelVersion> | |
3 | ||
4 | <parent> | |
5 | <groupId>net.postgis</groupId> | |
6 | <artifactId>postgis-java-aggregator</artifactId> | |
7 | <version>2021.1.0</version> | |
8 | </parent> | |
9 | ||
10 | <artifactId>postgis-geometry</artifactId> | |
11 | <version>2021.1.0</version> | |
12 | <packaging>jar</packaging> | |
13 | ||
14 | <name>PostGIS Geometry</name> | |
15 | <description>Geometry classes provided by PostGIS JDBC Extension</description> | |
16 | ||
17 | <properties /> | |
18 | ||
19 | <dependencies> | |
20 | <dependency> | |
21 | <groupId>net.postgis.tools</groupId> | |
22 | <artifactId>test-utils</artifactId> | |
23 | <version>2021.1.0</version> | |
24 | <scope>test</scope> | |
25 | </dependency> | |
26 | </dependencies> | |
27 | ||
28 | <build> | |
29 | <plugins> | |
30 | <plugin> | |
31 | <artifactId>maven-jar-plugin</artifactId> | |
32 | <configuration> | |
33 | <archive> | |
34 | <manifestEntries> | |
35 | <Automatic-Module-Name>net.postgis.jdbc.geometry</Automatic-Module-Name> | |
36 | </manifestEntries> | |
37 | </archive> | |
38 | </configuration> | |
39 | </plugin> | |
40 | </plugins> | |
41 | </build> | |
42 | ||
43 | </project> |
0 | module net.postgis.jdbc.geometry { | |
1 | requires java.sql; | |
2 | ||
3 | requires org.slf4j; | |
4 | ||
5 | exports net.postgis.jdbc.geometry; | |
6 | exports net.postgis.jdbc.geometry.binary; | |
7 | exports net.postgis.jdbc.geometry.util; | |
8 | }⏎ |
0 | /* | |
1 | * ComposedGeom.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc.geometry; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | import java.util.Iterator; | |
31 | import java.util.List; | |
32 | ||
33 | /** | |
34 | * ComposedGeom - Abstract base class for all Geometries that are composed out | |
35 | * of other Geometries. | |
36 | * | |
37 | * In fact, this currently are all Geometry subclasses except Point. | |
38 | * | |
39 | * @author markus.schaber@logix-tt.com | |
40 | * | |
41 | * | |
42 | */ | |
43 | public abstract class ComposedGeom extends Geometry { | |
44 | /* JDK 1.5 Serialization */ | |
45 | private static final long serialVersionUID = 0x100; | |
46 | ||
47 | public static final Geometry[] EMPTY = new Geometry[0]; | |
48 | ||
49 | /** | |
50 | * The Array containing the geometries | |
51 | * | |
52 | * This is only to be exposed by concrete subclasses, to retain type safety. | |
53 | */ | |
54 | protected Geometry[] subgeoms = EMPTY; | |
55 | ||
56 | /** | |
57 | * Constructs an instance with the specified type | |
58 | * | |
59 | * @param type int value corresponding to the geometry type. | |
60 | */ | |
61 | public ComposedGeom(int type) { | |
62 | super(type); | |
63 | } | |
64 | ||
65 | public Geometry getSubGeometry(int index) { | |
66 | return subgeoms[index]; | |
67 | } | |
68 | ||
69 | public int numGeoms() { | |
70 | return subgeoms.length; | |
71 | } | |
72 | ||
73 | protected ComposedGeom(int type, Geometry[] geoms) { | |
74 | this(type); | |
75 | this.subgeoms = geoms; | |
76 | if (geoms.length > 0) { | |
77 | dimension = geoms[0].dimension; | |
78 | haveMeasure = geoms[0].haveMeasure; | |
79 | } else { | |
80 | dimension = 0; | |
81 | } | |
82 | } | |
83 | ||
84 | protected ComposedGeom(int type, String value, boolean haveM) throws SQLException { | |
85 | super(type); | |
86 | value = initSRID(value); | |
87 | ||
88 | String typestring = getTypeString(); | |
89 | if (value.indexOf(typestring) == 0) { | |
90 | int pfxlen = typestring.length(); | |
91 | if (value.charAt(pfxlen) == 'M') { | |
92 | pfxlen += 1; | |
93 | haveM = true; | |
94 | } | |
95 | value = value.substring(pfxlen).trim(); | |
96 | } else if (value.charAt(0) != '(') { | |
97 | // we are neigher inner nor outer rep. | |
98 | throw new SQLException("Error parsing a " + typestring + " out of " + value); | |
99 | } | |
100 | if (value.equals("(EMPTY)")) { | |
101 | // Special case for PostGIS 0.X style empty geometry collections | |
102 | // (which are not OpenGIS compliant) | |
103 | return; | |
104 | } | |
105 | ||
106 | String valueNoParans = GeometryTokenizer.removeLeadingAndTrailingStrings(value, "(", ")"); | |
107 | List<String> tokens = GeometryTokenizer.tokenize(valueNoParans, ','); | |
108 | ||
109 | int subgeomcount = tokens.size(); | |
110 | subgeoms = createSubGeomArray(subgeomcount); | |
111 | for (int p = 0; p < subgeomcount; p++) { | |
112 | subgeoms[p] = createSubGeomInstance(tokens.get(p), haveM); | |
113 | } | |
114 | dimension = subgeoms[0].dimension; | |
115 | // fetch haveMeasure from sub-point because haveM does only work with | |
116 | // 2d+M, not with 3d+M geometries | |
117 | haveMeasure = subgeoms[0].haveMeasure; | |
118 | } | |
119 | ||
120 | /** | |
121 | * Return the appropriate instance of the sub-geometry - this encapsulates | |
122 | * subclass specific constructor calls | |
123 | * | |
124 | * @param token The token containing the value for the sub-geometry | |
125 | * @param haveM flag to indicate the existence of a measure | |
126 | * @return the new sub-geometry | |
127 | * @throws SQLException if a SQLException is thrown | |
128 | */ | |
129 | protected abstract Geometry createSubGeomInstance(String token, boolean haveM) throws SQLException; | |
130 | ||
131 | /** | |
132 | * Return the appropriate instance of the sub-geometry array - this | |
133 | * encapsulates subclass specific array instantiation | |
134 | * | |
135 | * @param size number of elements in the array | |
136 | * @return Geometry array corresponding to the sub-geometry | |
137 | */ | |
138 | protected abstract Geometry[] createSubGeomArray(int size); | |
139 | ||
140 | protected boolean equalsintern(Geometry other) { | |
141 | // Can be assumed to be the same subclass of Geometry, so it must be a | |
142 | // ComposedGeom, too. | |
143 | ComposedGeom cother = (ComposedGeom) other; | |
144 | ||
145 | if (cother.subgeoms == null && subgeoms == null) { | |
146 | return true; | |
147 | } else if (cother.subgeoms == null || subgeoms == null) { | |
148 | return false; | |
149 | } else if (cother.subgeoms.length != subgeoms.length) { | |
150 | return false; | |
151 | } else if (subgeoms.length == 0) { | |
152 | return true; | |
153 | } else { | |
154 | for (int i = 0; i < subgeoms.length; i++) { | |
155 | if (!cother.subgeoms[i].equalsintern(this.subgeoms[i])) { | |
156 | return false; | |
157 | } | |
158 | } | |
159 | } | |
160 | return true; | |
161 | } | |
162 | ||
163 | public int numPoints() { | |
164 | if ((subgeoms == null) || (subgeoms.length == 0)) { | |
165 | return 0; | |
166 | } else { | |
167 | int result = 0; | |
168 | for (int i = 0; i < subgeoms.length; i++) { | |
169 | result += subgeoms[i].numPoints(); | |
170 | } | |
171 | return result; | |
172 | } | |
173 | } | |
174 | ||
175 | public Point getPoint(int n) { | |
176 | if (n < 0) { | |
177 | throw new ArrayIndexOutOfBoundsException("Negative index not allowed"); | |
178 | } else if ((subgeoms == null) || (subgeoms.length == 0)) { | |
179 | throw new ArrayIndexOutOfBoundsException("Empty Geometry has no Points!"); | |
180 | } else { | |
181 | for (int i = 0; i < subgeoms.length; i++) { | |
182 | ||
183 | Geometry current = subgeoms[i]; | |
184 | int np = current.numPoints(); | |
185 | if (n < np) { | |
186 | return current.getPoint(n); | |
187 | } else { | |
188 | n -= np; | |
189 | } | |
190 | } | |
191 | throw new ArrayIndexOutOfBoundsException("Index too large!"); | |
192 | } | |
193 | } | |
194 | ||
195 | /** | |
196 | * Optimized version | |
197 | */ | |
198 | public Point getLastPoint() { | |
199 | if ((subgeoms == null) || (subgeoms.length == 0)) { | |
200 | throw new ArrayIndexOutOfBoundsException("Empty Geometry has no Points!"); | |
201 | } else { | |
202 | return subgeoms[subgeoms.length - 1].getLastPoint(); | |
203 | } | |
204 | } | |
205 | ||
206 | /** | |
207 | * Optimized version | |
208 | */ | |
209 | public Point getFirstPoint() { | |
210 | if ((subgeoms == null) || (subgeoms.length == 0)) { | |
211 | throw new ArrayIndexOutOfBoundsException("Empty Geometry has no Points!"); | |
212 | } else { | |
213 | return subgeoms[0].getFirstPoint(); | |
214 | } | |
215 | } | |
216 | ||
217 | public Iterator iterator() { | |
218 | return java.util.Arrays.asList(subgeoms).iterator(); | |
219 | } | |
220 | ||
221 | public boolean isEmpty() { | |
222 | return (subgeoms == null) || (subgeoms.length == 0); | |
223 | } | |
224 | ||
225 | protected void mediumWKT(StringBuffer sb) { | |
226 | if ((subgeoms == null) || (subgeoms.length == 0)) { | |
227 | sb.append(" EMPTY"); | |
228 | } else { | |
229 | sb.append('('); | |
230 | innerWKT(sb); | |
231 | sb.append(')'); | |
232 | } | |
233 | } | |
234 | ||
235 | protected void innerWKT(StringBuffer sb) { | |
236 | subgeoms[0].mediumWKT(sb); | |
237 | for (int i = 1; i < subgeoms.length; i++) { | |
238 | sb.append(','); | |
239 | subgeoms[i].mediumWKT(sb); | |
240 | } | |
241 | } | |
242 | ||
243 | // Hashing - still buggy! | |
244 | boolean nohash = true; | |
245 | int hashcode = 0; | |
246 | ||
247 | public int hashCode() { | |
248 | if (nohash) { | |
249 | hashcode = super.hashCode() ^ subgeoms.hashCode(); | |
250 | nohash = false; | |
251 | } | |
252 | return hashcode; | |
253 | } | |
254 | ||
255 | public boolean checkConsistency() { | |
256 | if (super.checkConsistency()) { | |
257 | if (isEmpty()) { | |
258 | return true; | |
259 | } | |
260 | // cache to avoid getMember opcode | |
261 | int _dimension = this.dimension; | |
262 | boolean _haveMeasure = this.haveMeasure; | |
263 | int _srid = this.srid; | |
264 | for (int i = 0; i < subgeoms.length; i++) { | |
265 | Geometry sub = subgeoms[i]; | |
266 | if (!(sub.checkConsistency() && sub.dimension == _dimension | |
267 | && sub.haveMeasure == _haveMeasure && sub.srid == _srid)) { | |
268 | return false; | |
269 | } | |
270 | } | |
271 | return true; | |
272 | } else { | |
273 | return false; | |
274 | } | |
275 | } | |
276 | ||
277 | public void setSrid(int srid) { | |
278 | super.setSrid(srid); | |
279 | for (int i = 0; i < subgeoms.length; i++) { | |
280 | subgeoms[i].setSrid(srid); | |
281 | } | |
282 | } | |
283 | } |
0 | /* | |
1 | * Geometry.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc.geometry; | |
28 | ||
29 | import java.io.Serializable; | |
30 | ||
31 | /** The base class of all geometries */ | |
32 | public abstract class Geometry implements Serializable { | |
33 | /* JDK 1.5 Serialization */ | |
34 | private static final long serialVersionUID = 0x100; | |
35 | ||
36 | // OpenGIS Geometry types as defined in the OGC WKB Spec | |
37 | // (May we replace this with an ENUM as soon as JDK 1.5 | |
38 | // has gained widespread usage?) | |
39 | ||
40 | /** Fake type for linear ring */ | |
41 | public static final int LINEARRING = 0; | |
42 | /** | |
43 | * The OGIS geometry type number for points. | |
44 | */ | |
45 | public static final int POINT = 1; | |
46 | ||
47 | /** | |
48 | * The OGIS geometry type number for lines. | |
49 | */ | |
50 | public static final int LINESTRING = 2; | |
51 | ||
52 | /** | |
53 | * The OGIS geometry type number for polygons. | |
54 | */ | |
55 | public static final int POLYGON = 3; | |
56 | ||
57 | /** | |
58 | * The OGIS geometry type number for aggregate points. | |
59 | */ | |
60 | public static final int MULTIPOINT = 4; | |
61 | ||
62 | /** | |
63 | * The OGIS geometry type number for aggregate lines. | |
64 | */ | |
65 | public static final int MULTILINESTRING = 5; | |
66 | ||
67 | /** | |
68 | * The OGIS geometry type number for aggregate polygons. | |
69 | */ | |
70 | public static final int MULTIPOLYGON = 6; | |
71 | ||
72 | /** | |
73 | * The OGIS geometry type number for feature collections. | |
74 | */ | |
75 | public static final int GEOMETRYCOLLECTION = 7; | |
76 | ||
77 | public static final String[] ALLTYPES = new String[] { | |
78 | "", // internally used LinearRing does not have any text in front of | |
79 | // it | |
80 | "POINT", "LINESTRING", "POLYGON", "MULTIPOINT", "MULTILINESTRING", | |
81 | "MULTIPOLYGON", "GEOMETRYCOLLECTION" }; | |
82 | ||
83 | /** | |
84 | * The Text representations of the geometry types | |
85 | * | |
86 | * @param type int value of the type to lookup | |
87 | * @return String reprentation of the type. | |
88 | */ | |
89 | public static String getTypeString(int type) { | |
90 | if (type >= 0 && type <= 7) { | |
91 | return ALLTYPES[type]; | |
92 | } else { | |
93 | throw new IllegalArgumentException("Unknown Geometry type" + type); | |
94 | } | |
95 | } | |
96 | ||
97 | // Properties common to all geometries | |
98 | /** | |
99 | * The dimensionality of this feature (2,3) | |
100 | */ | |
101 | public int dimension; | |
102 | ||
103 | /** | |
104 | * Do we have a measure (4th dimension) | |
105 | */ | |
106 | public boolean haveMeasure = false; | |
107 | ||
108 | /** | |
109 | * The OGIS geometry type of this feature. this is final as it never | |
110 | * changes, it is bound to the subclass of the instance. | |
111 | */ | |
112 | public final int type; | |
113 | ||
114 | /** | |
115 | * Official UNKNOWN srid value | |
116 | */ | |
117 | public final static int UNKNOWN_SRID = 0; | |
118 | ||
119 | /** | |
120 | * The spacial reference system id of this geometry, default is no srid | |
121 | */ | |
122 | public int srid = UNKNOWN_SRID; | |
123 | ||
124 | /** | |
125 | * Parse a SRID value, anything {@code <= 0} is unknown | |
126 | * | |
127 | * @param srid the SRID to parse | |
128 | * @return parsed SRID value | |
129 | */ | |
130 | public static int parseSRID(int srid) { | |
131 | if (srid < 0) { | |
132 | /* TODO: raise a warning ? */ | |
133 | srid = 0; | |
134 | } | |
135 | return srid; | |
136 | } | |
137 | ||
138 | /** | |
139 | * Constructor for subclasses | |
140 | * | |
141 | * @param type | |
142 | * has to be given by all subclasses. | |
143 | */ | |
144 | protected Geometry(int type) { | |
145 | this.type = type; | |
146 | } | |
147 | ||
148 | /** | |
149 | * java.lang.Object hashCode implementation | |
150 | */ | |
151 | public int hashCode() { | |
152 | return dimension | (type * 4) | (srid * 32); | |
153 | } | |
154 | ||
155 | /** | |
156 | * java.lang.Object equals implementation | |
157 | * | |
158 | * @param other geometry to compare | |
159 | * @return true if equal, false otherwise | |
160 | */ | |
161 | public boolean equals(Object other) { | |
162 | return (other != null) && (other instanceof Geometry) | |
163 | && equals((Geometry) other); | |
164 | } | |
165 | ||
166 | /** | |
167 | * geometry specific equals implementation - only defined for non-null | |
168 | * values | |
169 | * | |
170 | * @param other geometry to compare | |
171 | * @return true if equal, false otherwise | |
172 | */ | |
173 | public boolean equals(Geometry other) { | |
174 | return (other != null) && (this.dimension == other.dimension) | |
175 | && (this.type == other.type) && (this.srid == other.srid) | |
176 | && (this.haveMeasure == other.haveMeasure) | |
177 | && other.getClass().equals(this.getClass()) | |
178 | && this.equalsintern(other); | |
179 | } | |
180 | ||
181 | /** | |
182 | * Whether test coordinates for geometry - subclass specific code | |
183 | * | |
184 | * Implementors can assume that dimensin, type, srid and haveMeasure are | |
185 | * equal, other != null and other is the same subclass. | |
186 | * | |
187 | * @param other geometry to compare | |
188 | * @return true if equal, false otherwise | |
189 | */ | |
190 | protected abstract boolean equalsintern(Geometry other); | |
191 | ||
192 | /** | |
193 | * Return the number of Points of the geometry | |
194 | * | |
195 | * @return number of points in the geometry | |
196 | */ | |
197 | public abstract int numPoints(); | |
198 | ||
199 | /** | |
200 | * Get the nth Point of the geometry | |
201 | * | |
202 | * @param n the index of the point, from 0 to numPoints()-1; | |
203 | * @return nth point in the geometry | |
204 | * @throws ArrayIndexOutOfBoundsException in case of an emtpy geometry or bad index. | |
205 | */ | |
206 | public abstract Point getPoint(int n); | |
207 | ||
208 | /** | |
209 | * Same as getPoint(0); | |
210 | * | |
211 | * @return the initial Point in this geometry | |
212 | */ | |
213 | public abstract Point getFirstPoint(); | |
214 | ||
215 | /** | |
216 | * Same as getPoint(numPoints()-1); | |
217 | * | |
218 | * @return the final Point in this geometry | |
219 | */ | |
220 | public abstract Point getLastPoint(); | |
221 | ||
222 | /** | |
223 | * The OGIS geometry type number of this geometry. | |
224 | * | |
225 | * @return int value representation for the type of this geometry | |
226 | */ | |
227 | public int getType() { | |
228 | return this.type; | |
229 | } | |
230 | ||
231 | /** | |
232 | * Return the Type as String | |
233 | * | |
234 | * @return String representation for the type of this geometry | |
235 | */ | |
236 | public String getTypeString() { | |
237 | return getTypeString(this.type); | |
238 | } | |
239 | ||
240 | /** | |
241 | * Returns whether we have a measure | |
242 | * | |
243 | * @return true if the geometry has a measure, false otherwise | |
244 | */ | |
245 | public boolean isMeasured() { | |
246 | return haveMeasure; | |
247 | } | |
248 | ||
249 | /** | |
250 | * Queries the number of geometric dimensions of this geometry. This does | |
251 | * not include measures, as opposed to the server. | |
252 | * | |
253 | * @return The dimensionality (eg, 2D or 3D) of this geometry. | |
254 | */ | |
255 | public int getDimension() { | |
256 | return this.dimension; | |
257 | } | |
258 | ||
259 | /** | |
260 | * The OGIS geometry type number of this geometry. | |
261 | * | |
262 | * @return the SRID of this geometry | |
263 | */ | |
264 | public int getSrid() { | |
265 | return this.srid; | |
266 | } | |
267 | ||
268 | /** | |
269 | * Recursively sets the srid on this geometry and all contained | |
270 | * subgeometries | |
271 | * | |
272 | * @param srid the SRID for this geometry | |
273 | */ | |
274 | public void setSrid(int srid) { | |
275 | this.srid = srid; | |
276 | } | |
277 | ||
278 | public String toString() { | |
279 | StringBuffer sb = new StringBuffer(); | |
280 | if (srid != UNKNOWN_SRID) { | |
281 | sb.append("SRID="); | |
282 | sb.append(srid); | |
283 | sb.append(';'); | |
284 | } | |
285 | outerWKT(sb, true); | |
286 | return sb.toString(); | |
287 | } | |
288 | ||
289 | /** | |
290 | * Render the WKT version of this Geometry (without SRID) into the given | |
291 | * StringBuffer. | |
292 | * | |
293 | * @param sb StringBuffer to render into | |
294 | * @param putM flag to indicate if the M character should be used. | |
295 | */ | |
296 | public void outerWKT(StringBuffer sb, boolean putM) { | |
297 | sb.append(getTypeString()); | |
298 | if (putM && haveMeasure && dimension == 2) { | |
299 | sb.append('M'); | |
300 | } | |
301 | mediumWKT(sb); | |
302 | } | |
303 | ||
304 | public final void outerWKT(StringBuffer sb) { | |
305 | outerWKT(sb, true); | |
306 | } | |
307 | ||
308 | /** | |
309 | * Render the WKT without the type name, but including the brackets into the | |
310 | * StringBuffer | |
311 | * | |
312 | * @param sb StringBuffer to render into | |
313 | */ | |
314 | protected void mediumWKT(StringBuffer sb) { | |
315 | sb.append('('); | |
316 | innerWKT(sb); | |
317 | sb.append(')'); | |
318 | } | |
319 | ||
320 | /** | |
321 | * Render the "inner" part of the WKT (inside the brackets) into the | |
322 | * StringBuffer. | |
323 | * | |
324 | * @param SB StringBuffer to render into | |
325 | */ | |
326 | protected abstract void innerWKT(StringBuffer SB); | |
327 | ||
328 | /** | |
329 | * backwards compatibility method | |
330 | * | |
331 | * @return String representation of the value for the geometry. | |
332 | */ | |
333 | public String getValue() { | |
334 | StringBuffer sb = new StringBuffer(); | |
335 | mediumWKT(sb); | |
336 | return sb.toString(); | |
337 | } | |
338 | ||
339 | /** | |
340 | * Do some internal consistency checks on the geometry. | |
341 | * | |
342 | * Currently, all Geometries must have a valid dimension (2 or 3) and a | |
343 | * valid type. 2-dimensional Points must have Z=0.0, as well as non-measured | |
344 | * Points must have m=0.0. Composed geometries must have all equal SRID, | |
345 | * dimensionality and measures, as well as that they do not contain NULL or | |
346 | * inconsistent subgeometries. | |
347 | * | |
348 | * BinaryParser and WKTParser should only generate consistent geometries. | |
349 | * BinaryWriter may produce invalid results on inconsistent geometries. | |
350 | * | |
351 | * @return true if all checks are passed. | |
352 | */ | |
353 | public boolean checkConsistency() { | |
354 | return (dimension >= 2 && dimension <= 3) && (type >= 0 && type <= 7); | |
355 | } | |
356 | ||
357 | /** | |
358 | * Splits the SRID=4711; part of a EWKT rep if present and sets the srid. | |
359 | * | |
360 | * @param value String value to extract the SRID from | |
361 | * @return value without the SRID=4711; part | |
362 | */ | |
363 | protected String initSRID(String value) { | |
364 | value = value.trim(); | |
365 | if (value.startsWith("SRID=")) { | |
366 | int index = value.indexOf(';', 5); // sridprefix length is 5 | |
367 | if (index == -1) { | |
368 | throw new IllegalArgumentException( | |
369 | "Error parsing Geometry - SRID not delimited with ';' "); | |
370 | } else { | |
371 | this.srid = Integer.parseInt(value.substring(5, index)); | |
372 | return value.substring(index + 1).trim(); | |
373 | } | |
374 | } else { | |
375 | return value; | |
376 | } | |
377 | } | |
378 | } |
+115
-0
0 | package net.postgis.jdbc.geometry; | |
1 | ||
2 | ||
3 | import net.postgis.jdbc.geometry.binary.BinaryParser; | |
4 | ||
5 | import java.sql.SQLException; | |
6 | ||
7 | ||
8 | /** | |
9 | * Builds geometry instances. | |
10 | * | |
11 | * Note: This class contains the word "builder" but does NOT implement the builder pattern (yet). | |
12 | * | |
13 | * @author Phillip Ross | |
14 | */ | |
15 | public class GeometryBuilder { | |
16 | ||
17 | /** The prefix that indicates SRID presence */ | |
18 | public static final String SRIDPREFIX = "SRID="; | |
19 | ||
20 | ||
21 | public static Geometry geomFromString(String value) throws SQLException { | |
22 | return geomFromString(value, false); | |
23 | } | |
24 | ||
25 | public static Geometry geomFromString(String value, boolean haveM) throws SQLException { | |
26 | BinaryParser bp = new BinaryParser(); | |
27 | ||
28 | return geomFromString(value, bp, haveM); | |
29 | } | |
30 | ||
31 | /** | |
32 | * Maybe we could add more error checking here? | |
33 | * | |
34 | * @param value String representing the geometry | |
35 | * @param bp BinaryParser to use whe parsing | |
36 | * @return Geometry object parsed from the specified string value | |
37 | * @throws SQLException when a SQLException occurs | |
38 | */ | |
39 | public static Geometry geomFromString(String value, BinaryParser bp) throws SQLException { | |
40 | return geomFromString(value, bp, false); | |
41 | } | |
42 | ||
43 | public static Geometry geomFromString(String value, BinaryParser bp, boolean haveM) | |
44 | throws SQLException { | |
45 | value = value.trim(); | |
46 | ||
47 | int srid = Geometry.UNKNOWN_SRID; | |
48 | ||
49 | if (value.startsWith(SRIDPREFIX)) { | |
50 | // break up geometry into srid and wkt | |
51 | String[] parts = splitSRID(value); | |
52 | value = parts[1].trim(); | |
53 | srid = Geometry.parseSRID(Integer.parseInt(parts[0].substring(5))); | |
54 | } | |
55 | ||
56 | Geometry result; | |
57 | if (value.startsWith("00") || value.startsWith("01")) { | |
58 | result = bp.parse(value); | |
59 | } else if (value.endsWith("EMPTY")) { | |
60 | // We have a standard conforming representation for an empty | |
61 | // geometry which is to be parsed as an empty GeometryCollection. | |
62 | result = new GeometryCollection(); | |
63 | } else if (value.startsWith("MULTIPOLYGON")) { | |
64 | result = new MultiPolygon(value, haveM); | |
65 | } else if (value.startsWith("MULTILINESTRING")) { | |
66 | result = new MultiLineString(value, haveM); | |
67 | } else if (value.startsWith("MULTIPOINT")) { | |
68 | result = new MultiPoint(value, haveM); | |
69 | } else if (value.startsWith("POLYGON")) { | |
70 | result = new Polygon(value, haveM); | |
71 | } else if (value.startsWith("LINESTRING")) { | |
72 | result = new LineString(value, haveM); | |
73 | } else if (value.startsWith("POINT")) { | |
74 | result = new Point(value, haveM); | |
75 | } else if (value.startsWith("GEOMETRYCOLLECTION")) { | |
76 | result = new GeometryCollection(value, haveM); | |
77 | } else { | |
78 | throw new SQLException("Unknown type: " + value); | |
79 | } | |
80 | ||
81 | if (srid != Geometry.UNKNOWN_SRID) { | |
82 | result.srid = srid; | |
83 | } | |
84 | ||
85 | return result; | |
86 | } | |
87 | ||
88 | ||
89 | /** | |
90 | * Splits a String at the first occurrence of border character. | |
91 | * | |
92 | * Poor man's String.split() replacement, as String.split() was invented at | |
93 | * jdk1.4, and the Debian PostGIS Maintainer had problems building the woody | |
94 | * backport of his package using DFSG-free compilers. In all the cases we | |
95 | * used split() in the net.postgis package, we only needed to split at the | |
96 | * first occurence, and thus this code could even be faster. | |
97 | * | |
98 | * @param whole the String to be split | |
99 | * @return String array containing the split elements | |
100 | * @throws SQLException when a SQLException occurrs | |
101 | */ | |
102 | public static String[] splitSRID(String whole) throws SQLException { | |
103 | int index = whole.indexOf(';', 5); // sridprefix length is 5 | |
104 | if (index == -1) { | |
105 | throw new SQLException("Error parsing Geometry - SRID not delimited with ';' "); | |
106 | } else { | |
107 | return new String[]{ | |
108 | whole.substring(0, index), | |
109 | whole.substring(index + 1)}; | |
110 | } | |
111 | } | |
112 | ||
113 | ||
114 | } |
+82
-0
0 | /* | |
1 | * GeometryCollection.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc.geometry; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | ||
32 | /** | |
33 | * Geometry Collection class WARNING: Currently only implements empty | |
34 | * collections | |
35 | * | |
36 | * @author markus.schaber@logix-tt.com | |
37 | * | |
38 | */ | |
39 | ||
40 | public class GeometryCollection extends ComposedGeom { | |
41 | /* JDK 1.5 Serialization */ | |
42 | private static final long serialVersionUID = 0x100; | |
43 | ||
44 | public static final String GeoCollID = "GEOMETRYCOLLECTION"; | |
45 | ||
46 | public GeometryCollection() { | |
47 | super(GEOMETRYCOLLECTION); | |
48 | } | |
49 | ||
50 | public GeometryCollection(Geometry[] geoms) { | |
51 | super(GEOMETRYCOLLECTION, geoms); | |
52 | } | |
53 | ||
54 | public GeometryCollection(String value) throws SQLException { | |
55 | this(value, false); | |
56 | } | |
57 | ||
58 | public GeometryCollection(String value, boolean haveM) throws SQLException { | |
59 | super(GEOMETRYCOLLECTION, value, haveM); | |
60 | } | |
61 | ||
62 | protected Geometry[] createSubGeomArray(int ngeoms) { | |
63 | return new Geometry[ngeoms]; | |
64 | } | |
65 | ||
66 | protected Geometry createSubGeomInstance(String token, boolean haveM) throws SQLException { | |
67 | return GeometryBuilder.geomFromString(token, haveM); | |
68 | } | |
69 | ||
70 | protected void innerWKT(StringBuffer SB) { | |
71 | subgeoms[0].outerWKT(SB, true); | |
72 | for (int i = 1; i < subgeoms.length; i++) { | |
73 | SB.append(','); | |
74 | subgeoms[i].outerWKT(SB, true); | |
75 | } | |
76 | } | |
77 | ||
78 | public Geometry[] getGeometries() { | |
79 | return subgeoms; | |
80 | } | |
81 | } |
+76
-0
0 | /* | |
1 | * GeometryTokenizer.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | * | |
21 | */ | |
22 | ||
23 | package net.postgis.jdbc.geometry; | |
24 | ||
25 | ||
26 | import java.util.ArrayList; | |
27 | import java.util.List; | |
28 | import java.util.Stack; | |
29 | ||
30 | ||
31 | public class GeometryTokenizer { | |
32 | ||
33 | ||
34 | public static List<String> tokenize(String string, char delimiter) { | |
35 | List<String> tokens = new ArrayList<>(); | |
36 | Stack<Character> stack = new Stack<>(); | |
37 | int consumed = 0; | |
38 | for (int position = 0; position < string.length(); position++) { | |
39 | char character = string.charAt(position); | |
40 | if ((character == '(') || (character == '[')) { | |
41 | stack.push(character); | |
42 | } else if (((character == ')') && (stack.peek() == '(')) || | |
43 | ((character == ']') && (stack.peek() == '[')) | |
44 | ) { | |
45 | stack.pop(); | |
46 | } | |
47 | if ((character == delimiter) && (stack.size() == 0)) { | |
48 | tokens.add(string.substring(consumed, position)); | |
49 | consumed = position + 1; | |
50 | } | |
51 | } | |
52 | if (consumed < string.length()) { | |
53 | tokens.add(string.substring(consumed)); | |
54 | } | |
55 | return tokens; | |
56 | } | |
57 | ||
58 | ||
59 | public static String removeLeadingAndTrailingStrings(String string, String leadingString, String trailingString) { | |
60 | int startIndex = string.indexOf(leadingString); | |
61 | if (startIndex == -1) { | |
62 | startIndex = 0; | |
63 | } else { | |
64 | startIndex += leadingString.length(); | |
65 | } | |
66 | ||
67 | int endIndex = string.lastIndexOf(trailingString); | |
68 | if (endIndex == -1) { | |
69 | endIndex = string.length(); | |
70 | } | |
71 | return string.substring(startIndex, endIndex); | |
72 | } | |
73 | ||
74 | ||
75 | }⏎ |
0 | /* | |
1 | * LineString.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc.geometry; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | public class LineString extends PointComposedGeom { | |
32 | /* JDK 1.5 Serialization */ | |
33 | private static final long serialVersionUID = 0x100; | |
34 | ||
35 | double len = -1.; | |
36 | ||
37 | public LineString() { | |
38 | super(LINESTRING); | |
39 | } | |
40 | ||
41 | public LineString(Point[] points) { | |
42 | super(LINESTRING, points); | |
43 | } | |
44 | ||
45 | public LineString(String value) throws SQLException { | |
46 | super(LINESTRING, value); | |
47 | } | |
48 | ||
49 | public LineString(String value, boolean haveM) throws SQLException { | |
50 | super(LINESTRING, value, haveM); | |
51 | } | |
52 | ||
53 | public LineString reverse() { | |
54 | Point[] points = this.getPoints(); | |
55 | int l = points.length; | |
56 | int i, j; | |
57 | Point[] p = new Point[l]; | |
58 | for (i = 0, j = l - 1; i < l; i++, j--) { | |
59 | p[i] = points[j]; | |
60 | } | |
61 | return new LineString(p); | |
62 | } | |
63 | ||
64 | public LineString concat(LineString other) { | |
65 | Point[] points = this.getPoints(); | |
66 | Point[] opoints = other.getPoints(); | |
67 | ||
68 | boolean cutPoint = this.getLastPoint() == null | |
69 | || this.getLastPoint().equals(other.getFirstPoint()); | |
70 | int count = points.length + opoints.length - (cutPoint ? 1 : 0); | |
71 | Point[] p = new Point[count]; | |
72 | ||
73 | // Maybe we should use System.arrayCopy here? | |
74 | int i, j; | |
75 | for (i = 0; i < points.length; i++) { | |
76 | p[i] = points[i]; | |
77 | } | |
78 | if (!cutPoint) { | |
79 | p[i++] = other.getFirstPoint(); | |
80 | } | |
81 | for (j = 1; j < opoints.length; j++, i++) { | |
82 | p[i] = opoints[j]; | |
83 | } | |
84 | return new LineString(p); | |
85 | } | |
86 | ||
87 | public double length() { | |
88 | if (len < 0) { | |
89 | Point[] points = this.getPoints(); | |
90 | if ((points == null) || (points.length < 2)) { | |
91 | len = 0; | |
92 | } else { | |
93 | double sum = 0; | |
94 | for (int i = 1; i < points.length; i++) { | |
95 | sum += points[i - 1].distance(points[i]); | |
96 | } | |
97 | len = sum; | |
98 | } | |
99 | } | |
100 | return len; | |
101 | } | |
102 | } |
0 | /* | |
1 | * LinearRing.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc.geometry; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | import java.util.List; | |
31 | ||
32 | ||
33 | /** | |
34 | * This represents the LinearRing GIS datatype. This type is used to construct | |
35 | * the polygon types, but is not stored or retrieved directly from the database. | |
36 | */ | |
37 | public class LinearRing extends PointComposedGeom { | |
38 | /* JDK 1.5 Serialization */ | |
39 | private static final long serialVersionUID = 0x100; | |
40 | ||
41 | public LinearRing(Point[] points) { | |
42 | super(LINEARRING, points); | |
43 | } | |
44 | ||
45 | /** | |
46 | * This is called to construct a LinearRing from the PostGIS string | |
47 | * representation of a ring. | |
48 | * | |
49 | * @param value Definition of this ring in the PostGIS string format. | |
50 | * @throws SQLException when a SQLException occurs | |
51 | */ | |
52 | public LinearRing(String value) throws SQLException { | |
53 | this(value, false); | |
54 | } | |
55 | ||
56 | /** | |
57 | * @param value The text representation of this LinearRing | |
58 | * @param haveM Hint whether we have a measure. This is given to us by other | |
59 | * "parent" Polygon, and is passed further to our parent. | |
60 | * @throws SQLException when a SQLException occurs | |
61 | */ | |
62 | ||
63 | protected LinearRing(String value, boolean haveM) throws SQLException { | |
64 | super(LINEARRING); | |
65 | String valueNoParans = GeometryTokenizer.removeLeadingAndTrailingStrings(value.trim(), "(", ")"); | |
66 | List<String> tokens = GeometryTokenizer.tokenize(valueNoParans, ','); | |
67 | int npoints = tokens.size(); | |
68 | Point[] points = new Point[npoints]; | |
69 | for (int p = 0; p < npoints; p++) { | |
70 | points[p] = new Point(tokens.get(p), haveM); | |
71 | } | |
72 | this.dimension = points[0].dimension; | |
73 | // fetch haveMeasure from subpoint because haveM does only work with | |
74 | // 2d+M, not with 3d+M geometries | |
75 | this.haveMeasure = points[0].haveMeasure; | |
76 | this.subgeoms = points; | |
77 | } | |
78 | ||
79 | }⏎ |
0 | /* | |
1 | * MultiLineString.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc.geometry; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | public class MultiLineString extends ComposedGeom { | |
32 | /* JDK 1.5 Serialization */ | |
33 | private static final long serialVersionUID = 0x100; | |
34 | ||
35 | double len = -1; | |
36 | ||
37 | public int hashCode() { | |
38 | return super.hashCode() ^ (int) this.length(); | |
39 | } | |
40 | ||
41 | public MultiLineString() { | |
42 | super(MULTILINESTRING); | |
43 | } | |
44 | ||
45 | public MultiLineString(LineString[] lines) { | |
46 | super(MULTILINESTRING, lines); | |
47 | } | |
48 | ||
49 | public MultiLineString(String value) throws SQLException { | |
50 | this(value, false); | |
51 | } | |
52 | ||
53 | public MultiLineString(String value, boolean haveM) throws SQLException { | |
54 | super(MULTILINESTRING, value, haveM); | |
55 | } | |
56 | ||
57 | protected Geometry createSubGeomInstance(String token, boolean haveM) throws SQLException { | |
58 | return new LineString(token, haveM); | |
59 | } | |
60 | ||
61 | protected Geometry[] createSubGeomArray(int nlines) { | |
62 | return new LineString[nlines]; | |
63 | } | |
64 | ||
65 | public int numLines() { | |
66 | return subgeoms.length; | |
67 | } | |
68 | ||
69 | public LineString[] getLines() { | |
70 | return (LineString[]) subgeoms.clone(); | |
71 | } | |
72 | ||
73 | public LineString getLine(int idx) { | |
74 | if (idx >= 0 & idx < subgeoms.length) { | |
75 | return (LineString) subgeoms[idx]; | |
76 | } else { | |
77 | return null; | |
78 | } | |
79 | } | |
80 | ||
81 | public double length() { | |
82 | if (len < 0) { | |
83 | LineString[] lines = (LineString[]) subgeoms; | |
84 | if (lines.length < 1) { | |
85 | len = 0; | |
86 | } else { | |
87 | double sum = 0; | |
88 | for (int i = 0; i < lines.length; i++) { | |
89 | sum += lines[i].length(); | |
90 | } | |
91 | len = sum; | |
92 | } | |
93 | } | |
94 | return len; | |
95 | } | |
96 | } |
0 | /* | |
1 | * MultiPoint.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc.geometry; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | public class MultiPoint extends PointComposedGeom { | |
32 | /* JDK 1.5 Serialization */ | |
33 | private static final long serialVersionUID = 0x100; | |
34 | ||
35 | public MultiPoint() { | |
36 | super(MULTIPOINT); | |
37 | } | |
38 | ||
39 | public MultiPoint(Point[] points) { | |
40 | super(MULTIPOINT, points); | |
41 | } | |
42 | ||
43 | public MultiPoint(String value) throws SQLException { | |
44 | this(value, false); | |
45 | } | |
46 | ||
47 | protected MultiPoint(String value, boolean haveM) throws SQLException { | |
48 | super(MULTIPOINT, value, haveM); | |
49 | } | |
50 | } |
0 | /* | |
1 | * MultiPolygon.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc.geometry; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | public class MultiPolygon extends ComposedGeom { | |
32 | /* JDK 1.5 Serialization */ | |
33 | private static final long serialVersionUID = 0x100; | |
34 | ||
35 | public MultiPolygon() { | |
36 | super(MULTIPOLYGON); | |
37 | } | |
38 | ||
39 | public MultiPolygon(Polygon[] polygons) { | |
40 | super(MULTIPOLYGON, polygons); | |
41 | } | |
42 | ||
43 | public MultiPolygon(String value) throws SQLException { | |
44 | this(value, false); | |
45 | } | |
46 | ||
47 | protected MultiPolygon(String value, boolean haveM) throws SQLException { | |
48 | super(MULTIPOLYGON, value, haveM); | |
49 | } | |
50 | ||
51 | protected Geometry[] createSubGeomArray(int npolygons) { | |
52 | return new Polygon[npolygons]; | |
53 | } | |
54 | ||
55 | protected Geometry createSubGeomInstance(String token, boolean haveM) throws SQLException { | |
56 | return new Polygon(token, haveM); | |
57 | } | |
58 | ||
59 | public int numPolygons() { | |
60 | return subgeoms.length; | |
61 | } | |
62 | ||
63 | public Polygon getPolygon(int idx) { | |
64 | if (idx >= 0 & idx < subgeoms.length) { | |
65 | return (Polygon) subgeoms[idx]; | |
66 | } else { | |
67 | return null; | |
68 | } | |
69 | } | |
70 | ||
71 | public Polygon[] getPolygons() { | |
72 | return (Polygon[]) subgeoms; | |
73 | } | |
74 | } |
0 | /* | |
1 | * Point.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc.geometry; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | import java.util.List; | |
31 | ||
32 | public class Point extends Geometry { | |
33 | /* JDK 1.5 Serialization */ | |
34 | private static final long serialVersionUID = 0x100; | |
35 | ||
36 | public static final boolean CUTINTS = true; | |
37 | ||
38 | public int hashCode() { | |
39 | return super.hashCode() ^ hashCode(x) ^ hashCode(y) ^ hashCode(z) ^ hashCode(m); | |
40 | } | |
41 | ||
42 | public static int hashCode(double value) { | |
43 | long v = Double.doubleToLongBits(value); | |
44 | return (int) (v ^ (v >>> 32)); | |
45 | } | |
46 | ||
47 | protected boolean equalsintern(Geometry otherg) { | |
48 | Point other = (Point) otherg; | |
49 | return equals(other); | |
50 | } | |
51 | ||
52 | public static boolean double_equals(double a, double b) { | |
53 | if ( Double.isNaN(a) && Double.isNaN(b) ) { | |
54 | return true; | |
55 | } | |
56 | else { | |
57 | return (a == b); | |
58 | } | |
59 | } | |
60 | ||
61 | public final boolean equals(Point other) { | |
62 | boolean xequals = double_equals(x, other.x); | |
63 | boolean yequals = double_equals(y, other.y); | |
64 | boolean zequals = ((dimension == 2) || double_equals(z, other.z)); | |
65 | boolean mequals = ((haveMeasure == false) || double_equals(m,other.m)); | |
66 | boolean result = xequals && yequals && zequals && mequals; | |
67 | return result; | |
68 | } | |
69 | ||
70 | public Point getPoint(int index) { | |
71 | if (index == 0) { | |
72 | return this; | |
73 | } else { | |
74 | throw new ArrayIndexOutOfBoundsException("Point only has a single Point! " + index); | |
75 | } | |
76 | } | |
77 | ||
78 | /** Optimized versions for this special case */ | |
79 | public Point getFirstPoint() { | |
80 | return this; | |
81 | } | |
82 | ||
83 | /** Optimized versions for this special case */ | |
84 | public Point getLastPoint() { | |
85 | return this; | |
86 | } | |
87 | ||
88 | public int numPoints() { | |
89 | return 1; | |
90 | } | |
91 | ||
92 | /** | |
93 | * The X coordinate of the point. | |
94 | * In most long/lat systems, this is the longitude. | |
95 | */ | |
96 | public double x; | |
97 | ||
98 | /** | |
99 | * The Y coordinate of the point. | |
100 | * In most long/lat systems, this is the latitude. | |
101 | */ | |
102 | public double y; | |
103 | ||
104 | /** | |
105 | * The Z coordinate of the point. | |
106 | * In most long/lat systems, this is a radius from the | |
107 | * center of the earth, or the height / elevation over | |
108 | * the ground. | |
109 | */ | |
110 | public double z; | |
111 | ||
112 | /** | |
113 | * The measure of the point. | |
114 | */ | |
115 | public double m = 0.0; | |
116 | ||
117 | public Point() { | |
118 | super(POINT); | |
119 | } | |
120 | ||
121 | /** Constructs a new Point | |
122 | * @param x the longitude / x ordinate | |
123 | * @param y the latitude / y ordinate | |
124 | * @param z the radius / height / elevation / z ordinate | |
125 | */ | |
126 | public Point(double x, double y, double z) { | |
127 | this(); | |
128 | this.x = x; | |
129 | this.y = y; | |
130 | this.z = z; | |
131 | dimension = 3; | |
132 | } | |
133 | ||
134 | /** Constructs a new Point | |
135 | * @param x the longitude / x ordinate | |
136 | * @param y the latitude / y ordinate | |
137 | */ | |
138 | public Point(double x, double y) { | |
139 | this(); | |
140 | this.x = x; | |
141 | this.y = y; | |
142 | this.z = 0.0; | |
143 | dimension = 2; | |
144 | } | |
145 | ||
146 | /** | |
147 | * Construct a Point from EWKT. | |
148 | * | |
149 | * (3D and measures are legal, but SRID is not allowed). | |
150 | * | |
151 | * @param value String representation of the geometry. | |
152 | * @throws SQLException when a SQLException occurs | |
153 | */ | |
154 | public Point(String value) throws SQLException { | |
155 | this(value, false); | |
156 | } | |
157 | ||
158 | /** | |
159 | * Construct a Point | |
160 | * | |
161 | * @param value The text representation of this point | |
162 | * @param haveM Hint whether we have a measure. This is used by other | |
163 | * geometries parsing inner points where we only get "1 2 3 4" | |
164 | * like strings without the "POINT(" and ")" stuff. If there | |
165 | * acutally is a POINTM prefix, this overrides the given value. | |
166 | * However, POINT does not set it to false, as they can be | |
167 | * contained in measured collections, as in | |
168 | * "GEOMETRYCOLLECTIONM(POINT(0 0 0))". | |
169 | * @throws SQLException when a SQLException occurs | |
170 | */ | |
171 | protected Point(String value, boolean haveM) throws SQLException { | |
172 | this(); | |
173 | value = initSRID(value); | |
174 | ||
175 | if (value.indexOf("POINTM") == 0) { | |
176 | haveM = true; | |
177 | value = value.substring(6).trim(); | |
178 | } else if (value.indexOf("POINT") == 0) { | |
179 | value = value.substring(5).trim(); | |
180 | } | |
181 | String valueNoParans = GeometryTokenizer.removeLeadingAndTrailingStrings(value, "(", ")"); | |
182 | List<String> tokens = GeometryTokenizer.tokenize(valueNoParans, ' '); | |
183 | try { | |
184 | x = Double.valueOf(tokens.get(0)).doubleValue(); | |
185 | y = Double.valueOf(tokens.get(1)).doubleValue(); | |
186 | haveM |= tokens.size() == 4; | |
187 | if ((tokens.size() == 3 && !haveM) || (tokens.size() == 4)) { | |
188 | z = Double.valueOf(tokens.get(2)).doubleValue(); | |
189 | dimension = 3; | |
190 | } else { | |
191 | dimension = 2; | |
192 | } | |
193 | if (haveM) { | |
194 | m = Double.valueOf(tokens.get(dimension)).doubleValue(); | |
195 | } | |
196 | } catch (NumberFormatException e) { | |
197 | throw new SQLException("Error parsing Point: " + e.toString()); | |
198 | } | |
199 | haveMeasure = haveM; | |
200 | } | |
201 | ||
202 | public void innerWKT(StringBuffer sb) { | |
203 | sb.append(x); | |
204 | if (CUTINTS) | |
205 | cutint(sb); | |
206 | sb.append(' '); | |
207 | sb.append(y); | |
208 | if (CUTINTS) | |
209 | cutint(sb); | |
210 | if (dimension == 3) { | |
211 | sb.append(' '); | |
212 | sb.append(z); | |
213 | if (CUTINTS) | |
214 | cutint(sb); | |
215 | } | |
216 | if (haveMeasure) { | |
217 | sb.append(' '); | |
218 | sb.append(m); | |
219 | if (CUTINTS) | |
220 | cutint(sb); | |
221 | } | |
222 | } | |
223 | ||
224 | private static void cutint(StringBuffer sb) { | |
225 | int l = sb.length() - 2; | |
226 | if ((sb.charAt(l + 1) == '0') && (sb.charAt(l) == '.')) { | |
227 | sb.setLength(l); | |
228 | } | |
229 | } | |
230 | ||
231 | public double getX() { | |
232 | return x; | |
233 | } | |
234 | ||
235 | public double getY() { | |
236 | return y; | |
237 | } | |
238 | ||
239 | public double getZ() { | |
240 | return z; | |
241 | } | |
242 | ||
243 | public double getM() { | |
244 | return m; | |
245 | } | |
246 | ||
247 | public void setX(double x) { | |
248 | this.x = x; | |
249 | } | |
250 | ||
251 | public void setY(double y) { | |
252 | this.y = y; | |
253 | } | |
254 | ||
255 | public void setZ(double z) { | |
256 | this.z = z; | |
257 | } | |
258 | ||
259 | public void setM(double m) { | |
260 | haveMeasure = true; | |
261 | this.m = m; | |
262 | } | |
263 | ||
264 | public void setX(int x) { | |
265 | this.x = x; | |
266 | } | |
267 | ||
268 | public void setY(int y) { | |
269 | this.y = y; | |
270 | } | |
271 | ||
272 | public void setZ(int z) { | |
273 | this.z = z; | |
274 | } | |
275 | ||
276 | public double distance(Point other) { | |
277 | double tx, ty, tz; | |
278 | if (this.dimension != other.dimension) { | |
279 | throw new IllegalArgumentException("Points have different dimensions!"); | |
280 | } | |
281 | tx = this.x - other.x; | |
282 | switch (this.dimension) { | |
283 | case 1 : | |
284 | return Math.sqrt(tx * tx); | |
285 | case 2 : | |
286 | ty = this.y - other.y; | |
287 | return Math.sqrt(tx * tx + ty * ty); | |
288 | case 3 : | |
289 | ty = this.y - other.y; | |
290 | tz = this.z - other.z; | |
291 | return Math.sqrt(tx * tx + ty * ty + tz * tz); | |
292 | default : | |
293 | throw new IllegalArgumentException("Illegal dimension of Point" + this.dimension); | |
294 | } | |
295 | } | |
296 | ||
297 | public boolean checkConsistency() { | |
298 | return super.checkConsistency() && (this.dimension == 3 || this.z == 0.0) | |
299 | && (this.haveMeasure || this.m == 0.0); | |
300 | } | |
301 | } |
+101
-0
0 | /* | |
1 | * PointComposedGeom.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | package net.postgis.jdbc.geometry; | |
27 | ||
28 | import java.sql.SQLException; | |
29 | ||
30 | /** | |
31 | * PointComposedGeom - base class for all composed geoms that contain only | |
32 | * points. | |
33 | * | |
34 | * @author markus.schaber@logix-tt.com | |
35 | * | |
36 | */ | |
37 | ||
38 | public abstract class PointComposedGeom extends ComposedGeom { | |
39 | /* JDK 1.5 Serialization */ | |
40 | private static final long serialVersionUID = 0x100; | |
41 | ||
42 | protected PointComposedGeom(int type) { | |
43 | super(type); | |
44 | } | |
45 | ||
46 | protected PointComposedGeom(int type, Point[] points) { | |
47 | super(type, points); | |
48 | } | |
49 | ||
50 | public PointComposedGeom(int type, String value) throws SQLException { | |
51 | this(type, value, false); | |
52 | } | |
53 | ||
54 | public PointComposedGeom(int type, String value, boolean haveM) throws SQLException { | |
55 | super(type, value, haveM); | |
56 | } | |
57 | ||
58 | protected Geometry createSubGeomInstance(String token, boolean haveM) throws SQLException { | |
59 | return new Point(token, haveM); | |
60 | } | |
61 | ||
62 | protected Geometry[] createSubGeomArray(int pointcount) { | |
63 | return new Point[pointcount]; | |
64 | } | |
65 | ||
66 | protected void innerWKT(StringBuffer sb) { | |
67 | subgeoms[0].innerWKT(sb); | |
68 | for (int i = 1; i < subgeoms.length; i++) { | |
69 | sb.append(','); | |
70 | subgeoms[i].innerWKT(sb); | |
71 | } | |
72 | } | |
73 | ||
74 | /** | |
75 | * optimized version | |
76 | */ | |
77 | public int numPoints() { | |
78 | return subgeoms.length; | |
79 | } | |
80 | ||
81 | /** | |
82 | * optimized version | |
83 | */ | |
84 | public Point getPoint(int idx) { | |
85 | if (idx >= 0 & idx < subgeoms.length) { | |
86 | return (Point) subgeoms[idx]; | |
87 | } else { | |
88 | return null; | |
89 | } | |
90 | } | |
91 | ||
92 | /** | |
93 | * Get the underlying Point array | |
94 | * | |
95 | * @return an array of Points within this geometry | |
96 | */ | |
97 | public Point[] getPoints() { | |
98 | return (Point[]) subgeoms; | |
99 | } | |
100 | } |
0 | /* | |
1 | * Polygon.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - geometry model | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc.geometry; | |
28 | ||
29 | import java.sql.SQLException; | |
30 | ||
31 | public class Polygon extends ComposedGeom { | |
32 | /* JDK 1.5 Serialization */ | |
33 | private static final long serialVersionUID = 0x100; | |
34 | ||
35 | public Polygon() { | |
36 | super(POLYGON); | |
37 | } | |
38 | ||
39 | public Polygon(LinearRing[] rings) { | |
40 | super(POLYGON, rings); | |
41 | } | |
42 | ||
43 | public Polygon(String value) throws SQLException { | |
44 | this(value, false); | |
45 | } | |
46 | ||
47 | public Polygon(String value, boolean haveM) throws SQLException { | |
48 | super(POLYGON, value, haveM); | |
49 | } | |
50 | ||
51 | protected Geometry createSubGeomInstance(String token, boolean haveM) throws SQLException { | |
52 | return new LinearRing(token, haveM); | |
53 | } | |
54 | ||
55 | protected Geometry[] createSubGeomArray(int ringcount) { | |
56 | return new LinearRing[ringcount]; | |
57 | } | |
58 | ||
59 | public int numRings() { | |
60 | return subgeoms.length; | |
61 | } | |
62 | ||
63 | public LinearRing getRing(int idx) { | |
64 | if (idx >= 0 & idx < subgeoms.length) { | |
65 | return (LinearRing) subgeoms[idx]; | |
66 | } else { | |
67 | return null; | |
68 | } | |
69 | } | |
70 | } |
+246
-0
0 | /* | |
1 | * BinaryParser.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Parser | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | package net.postgis.jdbc.geometry.binary; | |
25 | ||
26 | import net.postgis.jdbc.geometry.Geometry; | |
27 | import net.postgis.jdbc.geometry.GeometryCollection; | |
28 | import net.postgis.jdbc.geometry.LineString; | |
29 | import net.postgis.jdbc.geometry.LinearRing; | |
30 | import net.postgis.jdbc.geometry.MultiLineString; | |
31 | import net.postgis.jdbc.geometry.MultiPoint; | |
32 | import net.postgis.jdbc.geometry.MultiPolygon; | |
33 | import net.postgis.jdbc.geometry.Point; | |
34 | import net.postgis.jdbc.geometry.Polygon; | |
35 | import net.postgis.jdbc.geometry.binary.ByteGetter.BinaryByteGetter; | |
36 | import net.postgis.jdbc.geometry.binary.ByteGetter.StringByteGetter; | |
37 | ||
38 | ||
39 | /** | |
40 | * Parse binary representation of geometries. | |
41 | * | |
42 | * It should be easy to add char[] and CharSequence ByteGetter instances, | |
43 | * although the latter one is not compatible with older jdks. | |
44 | * | |
45 | * I did not implement real unsigned 32-bit integers or emulate them with long, | |
46 | * as both java Arrays and Strings currently can have only 2^31-1 elements | |
47 | * (bytes), so we cannot even get or build Geometries with more than approx. | |
48 | * 2^28 coordinates (8 bytes each). | |
49 | * | |
50 | * @author {@literal Markus Schaber <markus.schaber@logix-tt.com>} | |
51 | * | |
52 | */ | |
53 | public class BinaryParser { | |
54 | ||
55 | /** | |
56 | * Get the appropriate ValueGetter for my endianness | |
57 | * | |
58 | * @param bytes The appropriate Byte Getter | |
59 | * | |
60 | * @return the ValueGetter | |
61 | */ | |
62 | public static ValueGetter valueGetterForEndian(ByteGetter bytes) { | |
63 | if (bytes.get(0) == ValueGetter.XDR.NUMBER) { // XDR | |
64 | return new ValueGetter.XDR(bytes); | |
65 | } else if (bytes.get(0) == ValueGetter.NDR.NUMBER) { | |
66 | return new ValueGetter.NDR(bytes); | |
67 | } else { | |
68 | throw new IllegalArgumentException("Unknown Endian type:" + bytes.get(0)); | |
69 | } | |
70 | } | |
71 | ||
72 | /** | |
73 | * Parse a hex encoded geometry | |
74 | * | |
75 | * Is synchronized to protect offset counter. (Unfortunately, Java does not | |
76 | * have neither call by reference nor multiple return values.) | |
77 | * | |
78 | * @param value String containing the data to be parsed | |
79 | * @return resulting geometry for the parsed data | |
80 | */ | |
81 | public synchronized Geometry parse(String value) { | |
82 | StringByteGetter bytes = new StringByteGetter(value); | |
83 | return parseGeometry(valueGetterForEndian(bytes)); | |
84 | } | |
85 | ||
86 | /** | |
87 | * Parse a binary encoded geometry. | |
88 | * | |
89 | * Is synchronized to protect offset counter. (Unfortunately, Java does not | |
90 | * have neither call by reference nor multiple return values.) | |
91 | * | |
92 | * @param value byte array containing the data to be parsed | |
93 | * @return resulting geometry for the parsed data | |
94 | */ | |
95 | public synchronized Geometry parse(byte[] value) { | |
96 | BinaryByteGetter bytes = new BinaryByteGetter(value); | |
97 | return parseGeometry(valueGetterForEndian(bytes)); | |
98 | } | |
99 | ||
100 | /** | |
101 | * Parse a geometry starting at offset. | |
102 | * | |
103 | * @param data ValueGetter with the data to be parsed | |
104 | * @return the parsed geometry | |
105 | * */ | |
106 | protected Geometry parseGeometry(ValueGetter data) { | |
107 | byte endian = data.getByte(); // skip and test endian flag | |
108 | if (endian != data.endian) { | |
109 | throw new IllegalArgumentException("Endian inconsistency!"); | |
110 | } | |
111 | int typeword = data.getInt(); | |
112 | ||
113 | int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits | |
114 | ||
115 | boolean haveZ = (typeword & 0x80000000) != 0; | |
116 | boolean haveM = (typeword & 0x40000000) != 0; | |
117 | boolean haveS = (typeword & 0x20000000) != 0; | |
118 | ||
119 | int srid = Geometry.UNKNOWN_SRID; | |
120 | ||
121 | if (haveS) { | |
122 | srid = Geometry.parseSRID(data.getInt()); | |
123 | } | |
124 | Geometry result1; | |
125 | switch (realtype) { | |
126 | case Geometry.POINT : | |
127 | result1 = parsePoint(data, haveZ, haveM); | |
128 | break; | |
129 | case Geometry.LINESTRING : | |
130 | result1 = parseLineString(data, haveZ, haveM); | |
131 | break; | |
132 | case Geometry.POLYGON : | |
133 | result1 = parsePolygon(data, haveZ, haveM); | |
134 | break; | |
135 | case Geometry.MULTIPOINT : | |
136 | result1 = parseMultiPoint(data); | |
137 | break; | |
138 | case Geometry.MULTILINESTRING : | |
139 | result1 = parseMultiLineString(data); | |
140 | break; | |
141 | case Geometry.MULTIPOLYGON : | |
142 | result1 = parseMultiPolygon(data); | |
143 | break; | |
144 | case Geometry.GEOMETRYCOLLECTION : | |
145 | result1 = parseCollection(data); | |
146 | break; | |
147 | default : | |
148 | throw new IllegalArgumentException("Unknown Geometry Type: " + realtype); | |
149 | } | |
150 | ||
151 | Geometry result = result1; | |
152 | ||
153 | if (srid != Geometry.UNKNOWN_SRID) { | |
154 | result.setSrid(srid); | |
155 | } | |
156 | return result; | |
157 | } | |
158 | ||
159 | private Point parsePoint(ValueGetter data, boolean haveZ, boolean haveM) { | |
160 | double X = data.getDouble(); | |
161 | double Y = data.getDouble(); | |
162 | Point result; | |
163 | if (haveZ) { | |
164 | double Z = data.getDouble(); | |
165 | result = new Point(X, Y, Z); | |
166 | } else { | |
167 | result = new Point(X, Y); | |
168 | } | |
169 | ||
170 | if (haveM) { | |
171 | result.setM(data.getDouble()); | |
172 | } | |
173 | ||
174 | return result; | |
175 | } | |
176 | ||
177 | /** Parse an Array of "full" Geometries */ | |
178 | private void parseGeometryArray(ValueGetter data, Geometry[] container) { | |
179 | for (int i = 0; i < container.length; i++) { | |
180 | container[i] = parseGeometry(data); | |
181 | } | |
182 | } | |
183 | ||
184 | /** | |
185 | * Parse an Array of "slim" Points (without endianness and type, part of | |
186 | * LinearRing and Linestring, but not MultiPoint! | |
187 | * | |
188 | * @param haveZ | |
189 | * @param haveM | |
190 | */ | |
191 | private Point[] parsePointArray(ValueGetter data, boolean haveZ, boolean haveM) { | |
192 | int count = data.getInt(); | |
193 | Point[] result = new Point[count]; | |
194 | for (int i = 0; i < count; i++) { | |
195 | result[i] = parsePoint(data, haveZ, haveM); | |
196 | } | |
197 | return result; | |
198 | } | |
199 | ||
200 | private MultiPoint parseMultiPoint(ValueGetter data) { | |
201 | Point[] points = new Point[data.getInt()]; | |
202 | parseGeometryArray(data, points); | |
203 | return new MultiPoint(points); | |
204 | } | |
205 | ||
206 | private LineString parseLineString(ValueGetter data, boolean haveZ, boolean haveM) { | |
207 | Point[] points = parsePointArray(data, haveZ, haveM); | |
208 | return new LineString(points); | |
209 | } | |
210 | ||
211 | private LinearRing parseLinearRing(ValueGetter data, boolean haveZ, boolean haveM) { | |
212 | Point[] points = parsePointArray(data, haveZ, haveM); | |
213 | return new LinearRing(points); | |
214 | } | |
215 | ||
216 | private Polygon parsePolygon(ValueGetter data, boolean haveZ, boolean haveM) { | |
217 | int count = data.getInt(); | |
218 | LinearRing[] rings = new LinearRing[count]; | |
219 | for (int i = 0; i < count; i++) { | |
220 | rings[i] = parseLinearRing(data, haveZ, haveM); | |
221 | } | |
222 | return new Polygon(rings); | |
223 | } | |
224 | ||
225 | private MultiLineString parseMultiLineString(ValueGetter data) { | |
226 | int count = data.getInt(); | |
227 | LineString[] strings = new LineString[count]; | |
228 | parseGeometryArray(data, strings); | |
229 | return new MultiLineString(strings); | |
230 | } | |
231 | ||
232 | private MultiPolygon parseMultiPolygon(ValueGetter data) { | |
233 | int count = data.getInt(); | |
234 | Polygon[] polys = new Polygon[count]; | |
235 | parseGeometryArray(data, polys); | |
236 | return new MultiPolygon(polys); | |
237 | } | |
238 | ||
239 | private GeometryCollection parseCollection(ValueGetter data) { | |
240 | int count = data.getInt(); | |
241 | Geometry[] geoms = new Geometry[count]; | |
242 | parseGeometryArray(data, geoms); | |
243 | return new GeometryCollection(geoms); | |
244 | } | |
245 | } |
+377
-0
0 | /* | |
1 | * BinaryWriter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Writer | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | package net.postgis.jdbc.geometry.binary; | |
25 | ||
26 | import net.postgis.jdbc.geometry.Geometry; | |
27 | import net.postgis.jdbc.geometry.GeometryCollection; | |
28 | import net.postgis.jdbc.geometry.LineString; | |
29 | import net.postgis.jdbc.geometry.LinearRing; | |
30 | import net.postgis.jdbc.geometry.MultiLineString; | |
31 | import net.postgis.jdbc.geometry.MultiPoint; | |
32 | import net.postgis.jdbc.geometry.MultiPolygon; | |
33 | import net.postgis.jdbc.geometry.Point; | |
34 | import net.postgis.jdbc.geometry.Polygon; | |
35 | ||
36 | ||
37 | /** | |
38 | * Create binary representation of geometries. Currently, only text rep (hexed) | |
39 | * implementation is tested. | |
40 | * | |
41 | * It should be easy to add char[] and CharSequence ByteGetter instances, | |
42 | * although the latter one is not compatible with older jdks. | |
43 | * | |
44 | * I did not implement real unsigned 32-bit integers or emulate them with long, | |
45 | * as both java Arrays and Strings currently can have only 2^31-1 elements | |
46 | * (bytes), so we cannot even get or build Geometries with more than approx. | |
47 | * 2^28 coordinates (8 bytes each). | |
48 | * | |
49 | * @author markus.schaber@logi-track.com | |
50 | * | |
51 | */ | |
52 | public class BinaryWriter { | |
53 | ||
54 | /** | |
55 | * Get the appropriate ValueGetter for my endianness | |
56 | * | |
57 | * @param bytes The ByteSetter to use | |
58 | * @param endian the endian for the ValueSetter to use | |
59 | * @return the ValueGetter | |
60 | */ | |
61 | public static ValueSetter valueSetterForEndian(ByteSetter bytes, byte endian) { | |
62 | if (endian == ValueSetter.XDR.NUMBER) { // XDR | |
63 | return new ValueSetter.XDR(bytes); | |
64 | } else if (endian == ValueSetter.NDR.NUMBER) { | |
65 | return new ValueSetter.NDR(bytes); | |
66 | } else { | |
67 | throw new IllegalArgumentException("Unknown Endian type:" + endian); | |
68 | } | |
69 | } | |
70 | ||
71 | /** | |
72 | * Write a hex encoded geometry | |
73 | * | |
74 | * Is synchronized to protect offset counter. (Unfortunately, Java does not | |
75 | * have neither call by reference nor multiple return values.) This is a | |
76 | * TODO item. | |
77 | * | |
78 | * The geometry you put in must be consistent, geom.checkConsistency() must | |
79 | * return true. If not, the result may be invalid WKB. | |
80 | * | |
81 | * @see Geometry#checkConsistency() the consistency checker | |
82 | * | |
83 | * @param geom the geometry to be written | |
84 | * @param REP endianness to write the bytes with | |
85 | * @return String containing the hex encoded geometry | |
86 | */ | |
87 | public synchronized String writeHexed(Geometry geom, byte REP) { | |
88 | int length = estimateBytes(geom); | |
89 | ByteSetter.StringByteSetter bytes = new ByteSetter.StringByteSetter(length); | |
90 | writeGeometry(geom, valueSetterForEndian(bytes, REP)); | |
91 | return bytes.result(); | |
92 | } | |
93 | ||
94 | public synchronized String writeHexed(Geometry geom) { | |
95 | return writeHexed(geom, ValueSetter.NDR.NUMBER); | |
96 | } | |
97 | ||
98 | /** | |
99 | * Write a binary encoded geometry. | |
100 | * | |
101 | * Is synchronized to protect offset counter. (Unfortunately, Java does not | |
102 | * have neither call by reference nor multiple return values.) This is a | |
103 | * TODO item. | |
104 | * | |
105 | * The geometry you put in must be consistent, geom.checkConsistency() must | |
106 | * return true. If not, the result may be invalid WKB. | |
107 | * | |
108 | * @see Geometry#checkConsistency() | |
109 | * | |
110 | * @param geom the geometry to be written | |
111 | * @param REP endianness to write the bytes with | |
112 | * @return byte array containing the encoded geometry | |
113 | */ | |
114 | public synchronized byte[] writeBinary(Geometry geom, byte REP) { | |
115 | int length = estimateBytes(geom); | |
116 | ByteSetter.BinaryByteSetter bytes = new ByteSetter.BinaryByteSetter(length); | |
117 | writeGeometry(geom, valueSetterForEndian(bytes, REP)); | |
118 | return bytes.result(); | |
119 | } | |
120 | ||
121 | public synchronized byte[] writeBinary(Geometry geom) { | |
122 | return writeBinary(geom, ValueSetter.NDR.NUMBER); | |
123 | } | |
124 | ||
125 | /** | |
126 | * Parse a geometry starting at offset. | |
127 | * @param geom the geometry to write | |
128 | * @param dest the value setting to be used for writing | |
129 | */ | |
130 | protected void writeGeometry(Geometry geom, ValueSetter dest) { | |
131 | // write endian flag | |
132 | dest.setByte(dest.endian); | |
133 | ||
134 | // write typeword | |
135 | int typeword = geom.type; | |
136 | if (geom.dimension == 3) { | |
137 | typeword |= 0x80000000; | |
138 | } | |
139 | if (geom.haveMeasure) { | |
140 | typeword |= 0x40000000; | |
141 | } | |
142 | if (geom.srid != Geometry.UNKNOWN_SRID) { | |
143 | typeword |= 0x20000000; | |
144 | } | |
145 | ||
146 | dest.setInt(typeword); | |
147 | ||
148 | if (geom.srid != Geometry.UNKNOWN_SRID) { | |
149 | dest.setInt(geom.srid); | |
150 | } | |
151 | ||
152 | switch (geom.type) { | |
153 | case Geometry.POINT : | |
154 | writePoint((Point) geom, dest); | |
155 | break; | |
156 | case Geometry.LINESTRING : | |
157 | writeLineString((LineString) geom, dest); | |
158 | break; | |
159 | case Geometry.POLYGON : | |
160 | writePolygon((Polygon) geom, dest); | |
161 | break; | |
162 | case Geometry.MULTIPOINT : | |
163 | writeMultiPoint((MultiPoint) geom, dest); | |
164 | break; | |
165 | case Geometry.MULTILINESTRING : | |
166 | writeMultiLineString((MultiLineString) geom, dest); | |
167 | break; | |
168 | case Geometry.MULTIPOLYGON : | |
169 | writeMultiPolygon((MultiPolygon) geom, dest); | |
170 | break; | |
171 | case Geometry.GEOMETRYCOLLECTION : | |
172 | writeCollection((GeometryCollection) geom, dest); | |
173 | break; | |
174 | default : | |
175 | throw new IllegalArgumentException("Unknown Geometry Type: " + geom.type); | |
176 | } | |
177 | } | |
178 | ||
179 | /** | |
180 | * Writes a "slim" Point (without endiannes, srid ant type, only the | |
181 | * ordinates and measure. Used by writeGeometry as ell as writePointArray. | |
182 | */ | |
183 | private void writePoint(Point geom, ValueSetter dest) { | |
184 | dest.setDouble(geom.x); | |
185 | dest.setDouble(geom.y); | |
186 | ||
187 | if (geom.dimension == 3) { | |
188 | dest.setDouble(geom.z); | |
189 | } | |
190 | ||
191 | if (geom.haveMeasure) { | |
192 | dest.setDouble(geom.m); | |
193 | } | |
194 | } | |
195 | ||
196 | /** Write an Array of "full" Geometries */ | |
197 | private void writeGeometryArray(Geometry[] container, ValueSetter dest) { | |
198 | for (int i = 0; i < container.length; i++) { | |
199 | writeGeometry(container[i], dest); | |
200 | } | |
201 | } | |
202 | ||
203 | /** | |
204 | * Write an Array of "slim" Points (without endianness, srid and type, part | |
205 | * of LinearRing and Linestring, but not MultiPoint! | |
206 | */ | |
207 | private void writePointArray(Point[] geom, ValueSetter dest) { | |
208 | // number of points | |
209 | dest.setInt(geom.length); | |
210 | for (int i = 0; i < geom.length; i++) { | |
211 | writePoint(geom[i], dest); | |
212 | } | |
213 | } | |
214 | ||
215 | private void writeMultiPoint(MultiPoint geom, ValueSetter dest) { | |
216 | dest.setInt(geom.numPoints()); | |
217 | writeGeometryArray(geom.getPoints(), dest); | |
218 | } | |
219 | ||
220 | private void writeLineString(LineString geom, ValueSetter dest) { | |
221 | writePointArray(geom.getPoints(), dest); | |
222 | } | |
223 | ||
224 | private void writeLinearRing(LinearRing geom, ValueSetter dest) { | |
225 | writePointArray(geom.getPoints(), dest); | |
226 | } | |
227 | ||
228 | private void writePolygon(Polygon geom, ValueSetter dest) { | |
229 | dest.setInt(geom.numRings()); | |
230 | for (int i = 0; i < geom.numRings(); i++) { | |
231 | writeLinearRing(geom.getRing(i), dest); | |
232 | } | |
233 | } | |
234 | ||
235 | private void writeMultiLineString(MultiLineString geom, ValueSetter dest) { | |
236 | dest.setInt(geom.numLines()); | |
237 | writeGeometryArray(geom.getLines(), dest); | |
238 | } | |
239 | ||
240 | private void writeMultiPolygon(MultiPolygon geom, ValueSetter dest) { | |
241 | dest.setInt(geom.numPolygons()); | |
242 | writeGeometryArray(geom.getPolygons(), dest); | |
243 | } | |
244 | ||
245 | private void writeCollection(GeometryCollection geom, ValueSetter dest) { | |
246 | dest.setInt(geom.numGeoms()); | |
247 | writeGeometryArray(geom.getGeometries(), dest); | |
248 | } | |
249 | ||
250 | /** | |
251 | * Estimate how much bytes a geometry will need in WKB. | |
252 | * | |
253 | * @param geom Geometry to estimate. | |
254 | * @return estimated number of bytes | |
255 | */ | |
256 | protected int estimateBytes(Geometry geom) { | |
257 | int result = 0; | |
258 | ||
259 | // write endian flag | |
260 | result += 1; | |
261 | ||
262 | // write typeword | |
263 | result += 4; | |
264 | ||
265 | if (geom.srid != Geometry.UNKNOWN_SRID) { | |
266 | result += 4; | |
267 | } | |
268 | ||
269 | switch (geom.type) { | |
270 | case Geometry.POINT : | |
271 | result += estimatePoint((Point) geom); | |
272 | break; | |
273 | case Geometry.LINESTRING : | |
274 | result += estimateLineString((LineString) geom); | |
275 | break; | |
276 | case Geometry.POLYGON : | |
277 | result += estimatePolygon((Polygon) geom); | |
278 | break; | |
279 | case Geometry.MULTIPOINT : | |
280 | result += estimateMultiPoint((MultiPoint) geom); | |
281 | break; | |
282 | case Geometry.MULTILINESTRING : | |
283 | result += estimateMultiLineString((MultiLineString) geom); | |
284 | break; | |
285 | case Geometry.MULTIPOLYGON : | |
286 | result += estimateMultiPolygon((MultiPolygon) geom); | |
287 | break; | |
288 | case Geometry.GEOMETRYCOLLECTION : | |
289 | result += estimateCollection((GeometryCollection) geom); | |
290 | break; | |
291 | default : | |
292 | throw new IllegalArgumentException("Unknown Geometry Type: " + geom.type); | |
293 | } | |
294 | return result; | |
295 | } | |
296 | ||
297 | private int estimatePoint(Point geom) { | |
298 | // x, y both have 8 bytes | |
299 | int result = 16; | |
300 | if (geom.dimension == 3) { | |
301 | result += 8; | |
302 | } | |
303 | ||
304 | if (geom.haveMeasure) { | |
305 | result += 8; | |
306 | } | |
307 | return result; | |
308 | } | |
309 | ||
310 | /** Write an Array of "full" Geometries */ | |
311 | private int estimateGeometryArray(Geometry[] container) { | |
312 | int result = 0; | |
313 | for (int i = 0; i < container.length; i++) { | |
314 | result += estimateBytes(container[i]); | |
315 | } | |
316 | return result; | |
317 | } | |
318 | ||
319 | /** | |
320 | * Write an Array of "slim" Points (without endianness and type, part of | |
321 | * LinearRing and Linestring, but not MultiPoint! | |
322 | */ | |
323 | private int estimatePointArray(Point[] geom) { | |
324 | // number of points | |
325 | int result = 4; | |
326 | ||
327 | // And the amount of the points itsself, in consistent geometries | |
328 | // all points have equal size. | |
329 | if (geom.length > 0) { | |
330 | result += geom.length * estimatePoint(geom[0]); | |
331 | } | |
332 | return result; | |
333 | } | |
334 | ||
335 | private int estimateMultiPoint(MultiPoint geom) { | |
336 | // int size | |
337 | int result = 4; | |
338 | if (geom.numPoints() > 0) { | |
339 | // We can shortcut here, as all subgeoms have the same fixed size | |
340 | result += geom.numPoints() * estimateBytes(geom.getFirstPoint()); | |
341 | } | |
342 | return result; | |
343 | } | |
344 | ||
345 | private int estimateLineString(LineString geom) { | |
346 | return estimatePointArray(geom.getPoints()); | |
347 | } | |
348 | ||
349 | private int estimateLinearRing(LinearRing geom) { | |
350 | return estimatePointArray(geom.getPoints()); | |
351 | } | |
352 | ||
353 | private int estimatePolygon(Polygon geom) { | |
354 | // int length | |
355 | int result = 4; | |
356 | for (int i = 0; i < geom.numRings(); i++) { | |
357 | result += estimateLinearRing(geom.getRing(i)); | |
358 | } | |
359 | return result; | |
360 | } | |
361 | ||
362 | private int estimateMultiLineString(MultiLineString geom) { | |
363 | // 4-byte count + subgeometries | |
364 | return 4 + estimateGeometryArray(geom.getLines()); | |
365 | } | |
366 | ||
367 | private int estimateMultiPolygon(MultiPolygon geom) { | |
368 | // 4-byte count + subgeometries | |
369 | return 4 + estimateGeometryArray(geom.getPolygons()); | |
370 | } | |
371 | ||
372 | private int estimateCollection(GeometryCollection geom) { | |
373 | // 4-byte count + subgeometries | |
374 | return 4 + estimateGeometryArray(geom.getGeometries()); | |
375 | } | |
376 | } |
+76
-0
0 | /* | |
1 | * ByteGetter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Parser | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package net.postgis.jdbc.geometry.binary; | |
26 | ||
27 | public abstract class ByteGetter { | |
28 | /** | |
29 | * Get a byte. | |
30 | * | |
31 | * @param index the index to get the value from | |
32 | * @return The result is returned as Int to eliminate sign problems when | |
33 | * or'ing several values together. | |
34 | */ | |
35 | public abstract int get(int index); | |
36 | ||
37 | public static class BinaryByteGetter extends ByteGetter { | |
38 | private byte[] array; | |
39 | ||
40 | public BinaryByteGetter(byte[] array) { | |
41 | this.array = array; | |
42 | } | |
43 | ||
44 | public int get(int index) { | |
45 | return array[index] & 0xFF; // mask out sign-extended bits. | |
46 | } | |
47 | } | |
48 | ||
49 | public static class StringByteGetter extends ByteGetter { | |
50 | private String rep; | |
51 | ||
52 | public StringByteGetter(String rep) { | |
53 | this.rep = rep; | |
54 | } | |
55 | ||
56 | public int get(int index) { | |
57 | index *= 2; | |
58 | int high = unhex(rep.charAt(index)); | |
59 | int low = unhex(rep.charAt(index + 1)); | |
60 | return (high << 4) + low; | |
61 | } | |
62 | ||
63 | public static byte unhex(char c) { | |
64 | if (c >= '0' && c <= '9') { | |
65 | return (byte) (c - '0'); | |
66 | } else if (c >= 'A' && c <= 'F') { | |
67 | return (byte) (c - 'A' + 10); | |
68 | } else if (c >= 'a' && c <= 'f') { | |
69 | return (byte) (c - 'a' + 10); | |
70 | } else { | |
71 | throw new IllegalArgumentException("No valid Hex char " + c); | |
72 | } | |
73 | } | |
74 | } | |
75 | } |
+88
-0
0 | /* | |
1 | * ByteSetter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Parser | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package net.postgis.jdbc.geometry.binary; | |
26 | ||
27 | public abstract class ByteSetter { | |
28 | ||
29 | /** | |
30 | * Set a byte. | |
31 | * | |
32 | * @param b byte value to set with | |
33 | * @param index index to set | |
34 | */ | |
35 | public abstract void set(byte b, int index); | |
36 | ||
37 | public static class BinaryByteSetter extends ByteSetter { | |
38 | private byte[] array; | |
39 | ||
40 | public BinaryByteSetter(int length) { | |
41 | this.array = new byte[length]; | |
42 | } | |
43 | ||
44 | public void set(byte b, int index) { | |
45 | array[index] = b; // mask out sign-extended bits. | |
46 | } | |
47 | ||
48 | public byte[] result() { | |
49 | return array; | |
50 | } | |
51 | ||
52 | public String toString() { | |
53 | char[] arr = new char[array.length]; | |
54 | for (int i=0; i<array.length; i++) { | |
55 | arr[i] = (char)(array[i]&0xFF); | |
56 | } | |
57 | return new String(arr); | |
58 | } | |
59 | } | |
60 | ||
61 | public static class StringByteSetter extends ByteSetter { | |
62 | protected static final char[] hextypes = "0123456789ABCDEF".toCharArray(); | |
63 | private char[] rep; | |
64 | ||
65 | public StringByteSetter(int length) { | |
66 | this.rep = new char[length * 2]; | |
67 | } | |
68 | ||
69 | public void set(byte b, int index) { | |
70 | index *= 2; | |
71 | rep[index] = hextypes[(b >>> 4) & 0xF]; | |
72 | rep[index + 1] = hextypes[b & 0xF]; | |
73 | } | |
74 | ||
75 | public char[] resultAsArray() { | |
76 | return rep; | |
77 | } | |
78 | ||
79 | public String result() { | |
80 | return new String(rep); | |
81 | } | |
82 | ||
83 | public String toString() { | |
84 | return new String(rep); | |
85 | } | |
86 | } | |
87 | } |
+125
-0
0 | /* | |
1 | * ValueGetter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Parser | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package net.postgis.jdbc.geometry.binary; | |
26 | ||
27 | public abstract class ValueGetter { | |
28 | ByteGetter data; | |
29 | int position; | |
30 | public final byte endian; | |
31 | ||
32 | public ValueGetter(ByteGetter data, byte endian) { | |
33 | this.data = data; | |
34 | this.endian = endian; | |
35 | } | |
36 | ||
37 | /** | |
38 | * Get a byte, should be equal for all endians | |
39 | * | |
40 | * @return the byte value | |
41 | */ | |
42 | public byte getByte() { | |
43 | return (byte) data.get(position++); | |
44 | } | |
45 | ||
46 | public int getInt() { | |
47 | int res = getInt(position); | |
48 | position += 4; | |
49 | return res; | |
50 | } | |
51 | ||
52 | public long getLong() { | |
53 | long res = getLong(position); | |
54 | position += 8; | |
55 | return res; | |
56 | } | |
57 | ||
58 | /** | |
59 | * Get a 32-Bit integer | |
60 | * | |
61 | * @param index the index to get the value from | |
62 | * @return the int value | |
63 | */ | |
64 | protected abstract int getInt(int index); | |
65 | ||
66 | /** | |
67 | * Get a long value. This is not needed directly, but as a nice side-effect | |
68 | * from GetDouble. | |
69 | * | |
70 | * @param index the index to get the value from | |
71 | * @return the long value | |
72 | */ | |
73 | protected abstract long getLong(int index); | |
74 | ||
75 | /** | |
76 | * Get a double. | |
77 | * | |
78 | * @return the double value | |
79 | */ | |
80 | public double getDouble() { | |
81 | long bitrep = getLong(); | |
82 | return Double.longBitsToDouble(bitrep); | |
83 | } | |
84 | ||
85 | public static class XDR extends ValueGetter { | |
86 | public static final byte NUMBER = 0; | |
87 | ||
88 | public XDR(ByteGetter data) { | |
89 | super(data, NUMBER); | |
90 | } | |
91 | ||
92 | protected int getInt(int index) { | |
93 | return (data.get(index) << 24) + (data.get(index + 1) << 16) | |
94 | + (data.get(index + 2) << 8) + data.get(index + 3); | |
95 | } | |
96 | ||
97 | protected long getLong(int index) { | |
98 | return ((long) data.get(index) << 56) + ((long) data.get(index + 1) << 48) | |
99 | + ((long) data.get(index + 2) << 40) + ((long) data.get(index + 3) << 32) | |
100 | + ((long) data.get(index + 4) << 24) + ((long) data.get(index + 5) << 16) | |
101 | + ((long) data.get(index + 6) << 8) + ((long) data.get(index + 7) << 0); | |
102 | } | |
103 | } | |
104 | ||
105 | public static class NDR extends ValueGetter { | |
106 | public static final byte NUMBER = 1; | |
107 | ||
108 | public NDR(ByteGetter data) { | |
109 | super(data, NUMBER); | |
110 | } | |
111 | ||
112 | protected int getInt(int index) { | |
113 | return (data.get(index + 3) << 24) + (data.get(index + 2) << 16) | |
114 | + (data.get(index + 1) << 8) + data.get(index); | |
115 | } | |
116 | ||
117 | protected long getLong(int index) { | |
118 | return ((long) data.get(index + 7) << 56) + ((long) data.get(index + 6) << 48) | |
119 | + ((long) data.get(index + 5) << 40) + ((long) data.get(index + 4) << 32) | |
120 | + ((long) data.get(index + 3) << 24) + ((long) data.get(index + 2) << 16) | |
121 | + ((long) data.get(index + 1) << 8) + ((long) data.get(index) << 0); | |
122 | } | |
123 | } | |
124 | } |
+144
-0
0 | /* | |
1 | * ValueSetter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Parser | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package net.postgis.jdbc.geometry.binary; | |
26 | ||
27 | public abstract class ValueSetter { | |
28 | ByteSetter data; | |
29 | int position=0; | |
30 | public final byte endian; | |
31 | ||
32 | public ValueSetter(ByteSetter data, byte endian) { | |
33 | this.data = data; | |
34 | this.endian = endian; | |
35 | } | |
36 | ||
37 | /** | |
38 | * Set a byte, should be equal for all endians | |
39 | * | |
40 | * @param value byte value to be set with. | |
41 | */ | |
42 | public void setByte(byte value) { | |
43 | data.set(value, position); | |
44 | position += 1; | |
45 | } | |
46 | ||
47 | public void setInt(int value) { | |
48 | setInt(value, position); | |
49 | position += 4; | |
50 | } | |
51 | ||
52 | public void setLong(long value) { | |
53 | setLong(value, position); | |
54 | position += 8; | |
55 | } | |
56 | ||
57 | /** | |
58 | * Set a 32-Bit integer | |
59 | * | |
60 | * @param value int value to be set with | |
61 | * @param index int value for the index | |
62 | * | |
63 | */ | |
64 | protected abstract void setInt(int value, int index); | |
65 | ||
66 | /** | |
67 | * Set a long value. This is not needed directly, but as a nice side-effect | |
68 | * from GetDouble. | |
69 | * | |
70 | * @param data int value to be set with | |
71 | * @param index int value for the index | |
72 | */ | |
73 | protected abstract void setLong(long data, int index); | |
74 | ||
75 | /** | |
76 | * Set a double. | |
77 | * | |
78 | * @param data double value to be set with | |
79 | */ | |
80 | public void setDouble(double data) { | |
81 | long bitrep = Double.doubleToLongBits(data); | |
82 | setLong(bitrep); | |
83 | } | |
84 | ||
85 | public String toString() { | |
86 | String name = getClass().getName(); | |
87 | int pointpos = name.lastIndexOf('.'); | |
88 | String klsName = name.substring(pointpos+1); | |
89 | return klsName+"('"+(data==null?"NULL":data.toString()+"')"); | |
90 | } | |
91 | ||
92 | public static class XDR extends ValueSetter { | |
93 | public static final byte NUMBER = 0; | |
94 | ||
95 | public XDR(ByteSetter data) { | |
96 | super(data, NUMBER); | |
97 | } | |
98 | ||
99 | protected void setInt(int value, int index) { | |
100 | data.set((byte) (value >>> 24), index); | |
101 | data.set((byte) (value >>> 16), index + 1); | |
102 | data.set((byte) (value >>> 8), index + 2); | |
103 | data.set((byte) value, index + 3); | |
104 | } | |
105 | ||
106 | protected void setLong(long value, int index) { | |
107 | data.set((byte) (value >>> 56), index); | |
108 | data.set((byte) (value >>> 48), index + 1); | |
109 | data.set((byte) (value >>> 40), index + 2); | |
110 | data.set((byte) (value >>> 32), index + 3); | |
111 | data.set((byte) (value >>> 24), index + 4); | |
112 | data.set((byte) (value >>> 16), index + 5); | |
113 | data.set((byte) (value >>> 8), index + 6); | |
114 | data.set((byte) value, index + 7); | |
115 | } | |
116 | } | |
117 | ||
118 | public static class NDR extends ValueSetter { | |
119 | public static final byte NUMBER = 1; | |
120 | ||
121 | public NDR(ByteSetter data) { | |
122 | super(data, NUMBER); | |
123 | } | |
124 | ||
125 | protected void setInt(int value, int index) { | |
126 | data.set((byte) (value >>> 24), index + 3); | |
127 | data.set((byte) (value >>> 16), index + 2); | |
128 | data.set((byte) (value >>> 8), index + 1); | |
129 | data.set((byte) value, index); | |
130 | } | |
131 | ||
132 | protected void setLong(long value, int index) { | |
133 | data.set((byte) (value >>> 56), index + 7); | |
134 | data.set((byte) (value >>> 48), index + 6); | |
135 | data.set((byte) (value >>> 40), index + 5); | |
136 | data.set((byte) (value >>> 32), index + 4); | |
137 | data.set((byte) (value >>> 24), index + 3); | |
138 | data.set((byte) (value >>> 16), index + 2); | |
139 | data.set((byte) (value >>> 8), index + 1); | |
140 | data.set((byte) value, index); | |
141 | } | |
142 | } | |
143 | } |
+71
-0
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2020 Phillip Ross, phillip.w.g.ross@gmail.com | |
16 | */ | |
17 | ||
18 | package net.postgis.jdbc.geometry.util; | |
19 | ||
20 | ||
21 | /** | |
22 | * An enumeration of existing version functions. | |
23 | * | |
24 | * @author Phillip Ross | |
25 | */ | |
26 | public enum VersionFunctions { | |
27 | ||
28 | /** The function to return the full version and build configuration info of the PostGIS Server. */ | |
29 | POSTGIS_FULL_VERSION, | |
30 | ||
31 | /** The function to return the version of the GDAL library. */ | |
32 | POSTGIS_GDAL_VERSION, | |
33 | ||
34 | /** The function to return the version of the GEOS library. */ | |
35 | POSTGIS_GEOS_VERSION, | |
36 | ||
37 | /** The function to return the build date of the PostGIS library. */ | |
38 | POSTGIS_LIB_BUILD_DATE, | |
39 | ||
40 | /** The function to return the version of the PostGIS library. */ | |
41 | POSTGIS_LIB_VERSION, | |
42 | ||
43 | /** The function to return the version of the libjson library. */ | |
44 | POSTGIS_LIBJSON_VERSION, | |
45 | ||
46 | /** The function to return the version of the libxml library. */ | |
47 | POSTGIS_LIBXML_VERSION, | |
48 | ||
49 | /** The function to return the version of the Proj library. */ | |
50 | POSTGIS_PROJ_VERSION, | |
51 | ||
52 | /** The function to return the version of the raster library. */ | |
53 | POSTGIS_RASTER_LIB_VERSION, | |
54 | ||
55 | /** The function to return the build date of the scripts. */ | |
56 | POSTGIS_SCRIPTS_BUILD_DATE, | |
57 | ||
58 | /** The function to return the version of the scripts installed in the database. */ | |
59 | POSTGIS_SCRIPTS_INSTALLED, | |
60 | ||
61 | /** The function to return the version of the scripts released with the installed PostGIS library. */ | |
62 | POSTGIS_SCRIPTS_RELEASED, | |
63 | ||
64 | /** The function to return the Subversion version of the PostGIS Server. */ | |
65 | POSTGIS_SVN_VERSION, | |
66 | ||
67 | /** The function to return the version of the PostGIS Server. */ | |
68 | POSTGIS_VERSION | |
69 | ||
70 | } |
+173
-0
0 | /* | |
1 | * This library is free software; you can redistribute it and/or | |
2 | * modify it under the terms of the GNU Lesser General Public | |
3 | * License as published by the Free Software Foundation; either | |
4 | * version 2.1 of the License, or (at your option) any later version. | |
5 | * | |
6 | * This library is distributed in the hope that it will be useful, | |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9 | * Lesser General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU Lesser General Public | |
12 | * License along with this library; if not, write to the Free Software | |
13 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
14 | * | |
15 | * (C) 2020 Phillip Ross, phillip.w.g.ross@gmail.com | |
16 | */ | |
17 | ||
18 | package net.postgis.jdbc.geometry.util; | |
19 | ||
20 | ||
21 | import org.slf4j.Logger; | |
22 | import org.slf4j.LoggerFactory; | |
23 | ||
24 | import java.sql.Connection; | |
25 | import java.sql.PreparedStatement; | |
26 | import java.sql.ResultSet; | |
27 | import java.sql.SQLException; | |
28 | import java.util.Objects; | |
29 | ||
30 | ||
31 | /** | |
32 | * Utility for working with PostGIS Server version. | |
33 | * | |
34 | * @author Phillip Ross | |
35 | */ | |
36 | public class VersionUtil { | |
37 | ||
38 | /** The static logger instance. */ | |
39 | private static final Logger logger = LoggerFactory.getLogger(VersionUtil.class); | |
40 | ||
41 | /** The string to match when determining a function does not exist from the content of an error message. */ | |
42 | public static final String NONEXISTENT_FUNCTION_ERROR_MESSAGE_CONTENT = "does not exist"; | |
43 | ||
44 | /** The token which separates version components within the PostGIS Server version. */ | |
45 | public static final String POSTGIS_SERVER_VERSION_SEPERATOR = "."; | |
46 | ||
47 | /** The number of seconds to wait for a connection validation operation. */ | |
48 | private static final int DEFAULT_CONNECTION_TIMEOUT = 60; | |
49 | ||
50 | ||
51 | /** | |
52 | * Query a specific version string from the datasource for a specified function. | |
53 | * | |
54 | * @param connection The connection to issue the version query function against. | |
55 | * @param function The version function to use for querying the version. | |
56 | * @return a string version for the specified function. | |
57 | * @throws SQLException when a jdbc exception occurs. | |
58 | */ | |
59 | public static String getVersionString(final Connection connection, final String function) throws SQLException { | |
60 | Objects.requireNonNull(connection, "Unable to retrieve version string from a null connection"); | |
61 | Objects.requireNonNull(function, "Unable to retrieve version string for a null function"); | |
62 | validateConnection(connection); | |
63 | ||
64 | String result = "-- unavailable -- "; | |
65 | try ( | |
66 | PreparedStatement statement = connection.prepareStatement("SELECT " + function + "()"); | |
67 | ResultSet resultSet = statement.executeQuery(); | |
68 | ) { | |
69 | if (resultSet.next()) { | |
70 | String version = resultSet.getString(1); | |
71 | if (version != null) { | |
72 | result = version.trim(); | |
73 | } else { | |
74 | result = "-- null result --"; | |
75 | } | |
76 | } else { | |
77 | result = "-- no result --"; | |
78 | } | |
79 | } catch (SQLException sqle) { | |
80 | // If the function does not exist, a SQLException will be thrown, but it should be caught and swallowed if | |
81 | // the non-existent function error message content is found in the error message. The SQLException might | |
82 | // be thrown for some other problem not related to the missing function, so rethrow it if it doesn't | |
83 | // contain the non-existent function error message content. | |
84 | if (!sqle.getMessage().contains(NONEXISTENT_FUNCTION_ERROR_MESSAGE_CONTENT)) { | |
85 | throw sqle; | |
86 | } | |
87 | } | |
88 | return result; | |
89 | } | |
90 | ||
91 | ||
92 | public static String retrievePostGISServerVersionString(final Connection connection) throws SQLException { | |
93 | Objects.requireNonNull( | |
94 | connection, "Unable to retrieve PostGIS server version string from a null connection" | |
95 | ); | |
96 | validateConnection(connection); | |
97 | String postGISVersionString = getVersionString(connection, VersionFunctions.POSTGIS_VERSION.toString()); | |
98 | logger.debug("retrieved PostGIS server version string: [{}]", postGISVersionString); | |
99 | return postGISVersionString; | |
100 | } | |
101 | ||
102 | ||
103 | public static String retrievePostGISServerVersion(final Connection connection) throws SQLException { | |
104 | Objects.requireNonNull(connection, "Unable to retrieve PostGIS version from a null connection"); | |
105 | validateConnection(connection); | |
106 | String versionString = retrievePostGISServerVersionString(connection); | |
107 | ||
108 | final String versionTerminatorString = " "; | |
109 | final String version; | |
110 | final int versionTerminatorIndex = versionString.indexOf(versionTerminatorString); | |
111 | if (versionTerminatorIndex == -1) { | |
112 | version = versionString; | |
113 | } else { | |
114 | version = versionString.substring(0, versionTerminatorIndex); | |
115 | } | |
116 | logger.debug("retrieved PostGIS server version: [{}]", version); | |
117 | return version; | |
118 | } | |
119 | ||
120 | ||
121 | public static String retrievePostGISServerMajorVersion(final Connection connection) throws SQLException { | |
122 | Objects.requireNonNull(connection, "Unable to retrieve PostGIS major version from a null connection"); | |
123 | validateConnection(connection); | |
124 | String version = retrievePostGISServerVersion(connection); | |
125 | final String majorVersion; | |
126 | final int majorVersionSeperatorIndex = version.indexOf(POSTGIS_SERVER_VERSION_SEPERATOR); | |
127 | if (majorVersionSeperatorIndex == -1) { | |
128 | majorVersion = version; | |
129 | } else { | |
130 | majorVersion = version.substring(0, majorVersionSeperatorIndex); | |
131 | } | |
132 | logger.debug("retrieved postGIS major version string: [{}]", majorVersion); | |
133 | return majorVersion; | |
134 | } | |
135 | ||
136 | ||
137 | public static String retrievePostGISServerMinorVersion(final Connection connection) throws SQLException { | |
138 | Objects.requireNonNull(connection, "Unable to retrieve PostGIS minor version from a null connection"); | |
139 | validateConnection(connection); | |
140 | String version = retrievePostGISServerVersion(connection); | |
141 | final String minorVersion; | |
142 | final int majorVersionSeperatorIndex = version.indexOf(POSTGIS_SERVER_VERSION_SEPERATOR); | |
143 | if (majorVersionSeperatorIndex == -1) { | |
144 | minorVersion = ""; | |
145 | } else { | |
146 | final int minorVersionSeperatorIndex = | |
147 | version.indexOf(POSTGIS_SERVER_VERSION_SEPERATOR, majorVersionSeperatorIndex + 1); | |
148 | if (minorVersionSeperatorIndex == -1) { | |
149 | minorVersion = version.substring(majorVersionSeperatorIndex + 1); | |
150 | } else { | |
151 | minorVersion = version.substring(majorVersionSeperatorIndex + 1, minorVersionSeperatorIndex); | |
152 | } | |
153 | } | |
154 | logger.debug("retrieved postGIS minor version string: [{}]", minorVersion); | |
155 | return minorVersion; | |
156 | } | |
157 | ||
158 | ||
159 | /** | |
160 | * Validates a connection. | |
161 | * | |
162 | * @param connection the connection to be validated. | |
163 | * @throws SQLException when connection is invalid | |
164 | */ | |
165 | private static void validateConnection(final Connection connection) throws SQLException { | |
166 | if (!connection.isValid(DEFAULT_CONNECTION_TIMEOUT)) { | |
167 | throw new SQLException("The connection was not valid."); | |
168 | } | |
169 | } | |
170 | ||
171 | ||
172 | } |
+6
-0
0 | /** | |
1 | * Utility classes. | |
2 | * | |
3 | * @author Phillip Ross | |
4 | */ | |
5 | package net.postgis.jdbc.geometry.util; |
0 | /* | |
1 | * DatatypesTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc.geometry; | |
28 | ||
29 | ||
30 | import org.slf4j.Logger; | |
31 | import org.slf4j.LoggerFactory; | |
32 | import org.testng.annotations.Test; | |
33 | ||
34 | import java.sql.SQLException; | |
35 | ||
36 | ||
37 | public class DatatypesTest { | |
38 | ||
39 | private static final Logger logger = LoggerFactory.getLogger(DatatypesTest.class); | |
40 | ||
41 | private static final String mlng_str = "MULTILINESTRING ((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"; | |
42 | ||
43 | private static final String mplg_str = "MULTIPOLYGON (((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))"; | |
44 | ||
45 | private static final String plg_str = "POLYGON ((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))"; | |
46 | ||
47 | private static final String lng_str = "LINESTRING (10 10 20,20 20 20, 50 50 50, 34 34 34)"; | |
48 | ||
49 | private static final String ptg_str = "POINT(10 10 20)"; | |
50 | ||
51 | private static final String lr_str = "(10 10 20,34 34 34, 23 19 23 , 10 10 11)"; | |
52 | ||
53 | ||
54 | @Test | |
55 | public void testLinearRing() throws SQLException { | |
56 | logger.trace("void testLinearRing()"); | |
57 | logger.info(lr_str); | |
58 | LinearRing lr = new LinearRing(lr_str); | |
59 | logger.info(lr.toString()); | |
60 | } | |
61 | ||
62 | ||
63 | @Test | |
64 | public void testPoint() throws SQLException { | |
65 | logger.trace("void testPoint()"); | |
66 | logger.info(ptg_str); | |
67 | Point ptg = new Point(ptg_str); | |
68 | logger.info(ptg.toString()); | |
69 | } | |
70 | ||
71 | ||
72 | @Test | |
73 | public void testLineString() throws SQLException { | |
74 | logger.trace("void testLineString()"); | |
75 | logger.info(lng_str); | |
76 | LineString lng = new LineString(lng_str); | |
77 | logger.info(lng.toString()); | |
78 | } | |
79 | ||
80 | ||
81 | @Test | |
82 | public void testPolygon() throws SQLException { | |
83 | logger.trace("void testPolygon()"); | |
84 | logger.info(plg_str); | |
85 | Polygon plg = new Polygon(plg_str); | |
86 | logger.info(plg.toString()); | |
87 | } | |
88 | ||
89 | ||
90 | @Test | |
91 | public void testMultiPolygon() throws SQLException { | |
92 | logger.trace("void testMultiPolygon()"); | |
93 | logger.info(mplg_str); | |
94 | MultiPolygon mplg = new MultiPolygon(mplg_str); | |
95 | logger.info(mplg.toString()); | |
96 | } | |
97 | ||
98 | ||
99 | @Test | |
100 | public void testMultiLineString() throws SQLException { | |
101 | logger.trace("void testMultiLineString()"); | |
102 | logger.info(mlng_str); | |
103 | MultiLineString mlng = new MultiLineString(mlng_str); | |
104 | logger.info(mlng.toString()); | |
105 | } | |
106 | ||
107 | ||
108 | }⏎ |
0 | /* | |
1 | * TokenizerTest.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | * | |
21 | */ | |
22 | ||
23 | package net.postgis.jdbc.geometry; | |
24 | ||
25 | import org.slf4j.Logger; | |
26 | import org.slf4j.LoggerFactory; | |
27 | import org.testng.annotations.Test; | |
28 | ||
29 | import java.util.List; | |
30 | ||
31 | ||
32 | public class TokenizerTest { | |
33 | ||
34 | private static final Logger logger = LoggerFactory.getLogger(TokenizerTest.class); | |
35 | ||
36 | ||
37 | @Test | |
38 | public void testTokenizer() { | |
39 | char delimiterL1 = ','; | |
40 | char delimiterL2 = ' '; | |
41 | String stringToTokenize = "((1 2 3),(4 5 6),(7 8 9)"; | |
42 | logger.debug("tokenizing string value => {}", stringToTokenize); | |
43 | List<String> tokensLevel1 = GeometryTokenizer.tokenize(GeometryTokenizer.removeLeadingAndTrailingStrings(stringToTokenize, "(", ")"), delimiterL1); | |
44 | logger.debug("level 1 tokens [delimiter = {}] [tokenCount = {}]", delimiterL1, tokensLevel1.size()); | |
45 | for (String tokenL1 : tokensLevel1) { | |
46 | logger.debug("L1 token => {} / {}", tokenL1, GeometryTokenizer.removeLeadingAndTrailingStrings(tokenL1, "(", ")")); | |
47 | List<String> tokensLevel2 = GeometryTokenizer.tokenize(GeometryTokenizer.removeLeadingAndTrailingStrings(tokenL1, "(", ")"), delimiterL2); | |
48 | logger.debug("level 2 tokens [delimiter = {}] [tokenCount = {}]", delimiterL2, tokensLevel2.size()); | |
49 | for (String tokenL2 : tokensLevel2) { | |
50 | logger.debug("L2 token => {} / {}", tokenL2, GeometryTokenizer.removeLeadingAndTrailingStrings(tokenL2, "(", ")")); | |
51 | } | |
52 | } | |
53 | } | |
54 | ||
55 | }⏎ |
0 | <configuration debug="false"> | |
1 | ||
2 | <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | |
3 | <layout class="ch.qos.logback.classic.PatternLayout"> | |
4 | <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> | |
5 | </layout> | |
6 | </appender> | |
7 | ||
8 | <root level="debug"> | |
9 | <appender-ref ref="STDOUT" /> | |
10 | </root> | |
11 | ||
12 | <logger name="com.github.dockerjava" level="ERROR"/> | |
13 | <logger name="org.testcontainers" level="ERROR"/> | |
14 | <logger name="net.postgis" level="ERROR"/> | |
15 | ||
16 | </configuration>⏎ |
0 | <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> | |
1 | <suite name="Postgis Geometry Test Suite" verbose="1"> | |
2 | ||
3 | <test name="Postgis Geometry Tests"> | |
4 | <classes> | |
5 | <class name="net.postgis.jdbc.geometry.DatatypesTest"/> | |
6 | <class name="net.postgis.jdbc.geometry.TokenizerTest"/> | |
7 | </classes> | |
8 | </test> | |
9 | ||
10 | </suite>⏎ |
4 | 4 | <parent> |
5 | 5 | <groupId>net.postgis</groupId> |
6 | 6 | <artifactId>postgis-java-aggregator</artifactId> |
7 | <version>2.5.0</version> | |
7 | <version>2021.1.0</version> | |
8 | 8 | </parent> |
9 | 9 | |
10 | 10 | <artifactId>postgis-jdbc-java2d</artifactId> |
11 | <version>2.5.0</version> | |
11 | <version>2021.1.0</version> | |
12 | 12 | <packaging>jar</packaging> |
13 | 13 | |
14 | 14 | <name>postgis-jdbc-java2d</name> |
18 | 18 | <dependency> |
19 | 19 | <groupId>net.postgis</groupId> |
20 | 20 | <artifactId>postgis-jdbc</artifactId> |
21 | <version>2.5.0</version> | |
21 | <version>2021.1.0</version> | |
22 | 22 | </dependency> |
23 | 23 | <dependency> |
24 | 24 | <groupId>net.postgis.tools</groupId> |
25 | 25 | <artifactId>test-utils</artifactId> |
26 | <version>2.5.0</version> | |
26 | <version>2021.1.0</version> | |
27 | 27 | <scope>test</scope> |
28 | 28 | </dependency> |
29 | 29 | </dependencies> |
31 | 31 | <build> |
32 | 32 | <plugins> |
33 | 33 | <plugin> |
34 | <groupId>org.apache.maven.plugins</groupId> | |
35 | <artifactId>maven-surefire-plugin</artifactId> | |
34 | <artifactId>maven-jar-plugin</artifactId> | |
36 | 35 | <configuration> |
37 | <suiteXmlFiles> | |
38 | <suiteXmlFile>${project.build.testOutputDirectory}/testng.xml</suiteXmlFile> | |
39 | </suiteXmlFiles> | |
36 | <archive> | |
37 | <manifestEntries> | |
38 | <Automatic-Module-Name>net.postgis.jdbc.java2d</Automatic-Module-Name> | |
39 | </manifestEntries> | |
40 | </archive> | |
40 | 41 | </configuration> |
41 | 42 | </plugin> |
42 | 43 | </plugins> |
0 | /* | |
1 | * TestJava2d.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package examples; | |
28 | ||
29 | import java.awt.*; | |
30 | import java.awt.event.WindowEvent; | |
31 | import java.awt.event.WindowListener; | |
32 | import java.awt.geom.AffineTransform; | |
33 | import java.awt.geom.Rectangle2D; | |
34 | import java.sql.Connection; | |
35 | import java.sql.DriverManager; | |
36 | import java.sql.ResultSet; | |
37 | import java.sql.SQLException; | |
38 | import java.util.ArrayList; | |
39 | ||
40 | import org.postgis.java2d.Java2DWrapper; | |
41 | ||
42 | public class TestJava2d { | |
43 | private static final boolean DEBUG = true; | |
44 | ||
45 | public static final Shape[] SHAPEARRAY = new Shape[0]; | |
46 | ||
47 | public static final String[][] testDataset = new String[][] { | |
48 | {"point1", "POINT(10 11)"}, | |
49 | {"multipoint1", "MULTIPOINT(10.25 11,10.5 11,10.75 11,11 11,11.25 11,11.5 11,11.75 11,12 11)"}, | |
50 | {"linestring1", "LINESTRING(0 0,100 0,100 100,0 100)"}, | |
51 | {"linestring2", "LINESTRING(-310 110,210 110,210 210,-310 210,-310 110)"}, | |
52 | {"multilinestring", "MULTILINESTRING((0 0,10 10,20 0,30 10),(40 0,40 10,50 10,50 20,60 20))"}, | |
53 | }; | |
54 | ||
55 | static { | |
56 | new Java2DWrapper(); // make shure our driver is initialized | |
57 | } | |
58 | ||
59 | public static void main(String[] args) throws ClassNotFoundException, SQLException { | |
60 | ||
61 | if (args.length != 5) { | |
62 | System.err.println("Usage: java examples/TestJava2D dburl user pass tablename column"); | |
63 | System.err.println(); | |
64 | System.err.println("dburl has the following format:"); | |
65 | System.err.println(Java2DWrapper.POSTGIS_PROTOCOL + "//HOST:PORT/DATABASENAME"); | |
66 | System.err.println("tablename is 'jdbc_test' by default."); | |
67 | System.exit(1); | |
68 | } | |
69 | ||
70 | Shape[] geometries = read(args[0], args[1], args[2], "SELECT " + args[4] + " FROM " + args[3]); | |
71 | if (DEBUG) { | |
72 | System.err.println("read " + geometries.length + " geometries."); | |
73 | } | |
74 | if (geometries.length == 0) { | |
75 | if (DEBUG) { | |
76 | System.err.println("No geometries were read."); | |
77 | } | |
78 | return; | |
79 | } | |
80 | ||
81 | System.err.println("Painting..."); | |
82 | Frame window = new Frame("PostGIS java2D demo"); | |
83 | ||
84 | Canvas CV = new GisCanvas(geometries); | |
85 | ||
86 | window.add(CV); | |
87 | ||
88 | window.setSize(500, 500); | |
89 | ||
90 | window.addWindowListener(new EventHandler()); | |
91 | ||
92 | window.setVisible(true); | |
93 | } | |
94 | ||
95 | static Rectangle2D calcbbox(Shape[] geometries) { | |
96 | Rectangle2D bbox = geometries[0].getBounds2D(); | |
97 | for (int i = 1; i < geometries.length; i++) { | |
98 | bbox = bbox.createUnion(geometries[i].getBounds2D()); | |
99 | } | |
100 | return bbox; | |
101 | } | |
102 | ||
103 | private static Shape[] read(String dburl, String dbuser, String dbpass, String query) | |
104 | throws ClassNotFoundException, SQLException { | |
105 | ArrayList geometries = new ArrayList(); | |
106 | if (DEBUG) { | |
107 | System.err.println("Creating JDBC connection..."); | |
108 | } | |
109 | Class.forName("org.postgresql.Driver"); | |
110 | Connection conn = DriverManager.getConnection(dburl, dbuser, dbpass); | |
111 | ||
112 | if (DEBUG) { | |
113 | System.err.println("fetching geometries: " + query); | |
114 | } | |
115 | ResultSet r = conn.createStatement().executeQuery(query); | |
116 | ||
117 | while (r.next()) { | |
118 | final Shape current = (Shape) r.getObject(1); | |
119 | if (current != null) { | |
120 | geometries.add(current); | |
121 | } | |
122 | } | |
123 | conn.close(); | |
124 | return (Shape[]) geometries.toArray(SHAPEARRAY); | |
125 | } | |
126 | ||
127 | public static class GisCanvas extends Canvas { | |
128 | /** Keep java 1.5 compiler happy */ | |
129 | private static final long serialVersionUID = 1L; | |
130 | ||
131 | final Rectangle2D bbox; | |
132 | final Shape[] geometries; | |
133 | ||
134 | public GisCanvas(Shape[] geometries) { | |
135 | this.geometries = geometries; | |
136 | this.bbox = calcbbox(geometries); | |
137 | setBackground(Color.GREEN); | |
138 | } | |
139 | ||
140 | public void paint(Graphics og) { | |
141 | Graphics2D g = (Graphics2D) og; | |
142 | // Add 5% padding on all borders | |
143 | final double paddingTop = bbox.getHeight() * 0.05; | |
144 | final double paddingBottom = bbox.getHeight() * 0.05; | |
145 | final double paddingLeft = bbox.getWidth() * 0.05; | |
146 | final double paddingRight = bbox.getWidth() * 0.05; | |
147 | // If the bounding box has negative coordinates, we need to offset by the negative coordinate | |
148 | final double offsetX = (bbox.getX() < 0) ? (0 - bbox.getX()) : 0; | |
149 | final double offsetY = (bbox.getY() < 0) ? (0 - bbox.getY()) : 0; | |
150 | // Scale by the bounding box and padding | |
151 | final double scaleX = (super.getWidth() - (paddingLeft + paddingRight)) / (bbox.getWidth()); | |
152 | final double scaleY = (super.getHeight() - (paddingTop + paddingBottom)) / (bbox.getHeight()); | |
153 | // Apply the transform parameters | |
154 | AffineTransform at = new AffineTransform(); | |
155 | at.translate(paddingLeft, paddingTop); | |
156 | at.scale(scaleX, scaleY); | |
157 | at.translate(offsetX, offsetY); | |
158 | ||
159 | if (DEBUG) { | |
160 | System.err.println(); | |
161 | System.err.println("paddingTop: " + paddingTop); | |
162 | System.err.println("paddingBottom: " + paddingBottom); | |
163 | System.err.println("paddingLeft: " + paddingLeft); | |
164 | System.err.println("paddingRight: " + paddingRight); | |
165 | System.err.println("offsetX: " + offsetX); | |
166 | System.err.println("offsetY: " + offsetY); | |
167 | System.err.println("scaleX: " + scaleX); | |
168 | System.err.println("scaleY: " + scaleY); | |
169 | System.err.println("bbox: " + bbox); | |
170 | System.err.println("trans: " + at); | |
171 | System.err.println("new: " + at.createTransformedShape(bbox).getBounds2D()); | |
172 | System.err.println("visual:" + super.getBounds()); | |
173 | } | |
174 | for (int i = 0; i < geometries.length; i++) { | |
175 | g.setPaint(Color.BLUE); | |
176 | final Shape shape = at.createTransformedShape(geometries[i]); | |
177 | g.fill(shape); | |
178 | g.setPaint(Color.ORANGE); | |
179 | g.draw(shape); | |
180 | } | |
181 | } | |
182 | } | |
183 | ||
184 | public static class EventHandler implements WindowListener { | |
185 | ||
186 | public void windowActivated(WindowEvent e) {// | |
187 | } | |
188 | ||
189 | public void windowClosed(WindowEvent e) {// | |
190 | } | |
191 | ||
192 | public void windowClosing(WindowEvent e) { | |
193 | e.getWindow().setVisible(false); | |
194 | System.exit(0); | |
195 | } | |
196 | ||
197 | public void windowDeactivated(WindowEvent e) {// | |
198 | } | |
199 | ||
200 | public void windowDeiconified(WindowEvent e) {// | |
201 | } | |
202 | ||
203 | public void windowIconified(WindowEvent e) {// | |
204 | } | |
205 | ||
206 | public void windowOpened(WindowEvent e) {// | |
207 | } | |
208 | } | |
209 | }⏎ |
0 | module net.postgis.jdbc.java2d { | |
1 | requires java.desktop; | |
2 | requires java.sql; | |
3 | ||
4 | requires org.postgresql.jdbc; | |
5 | ||
6 | requires net.postgis.geometry; | |
7 | requires net.postgis.jdbc; | |
8 | ||
9 | exports net.postgis.jdbc.java2d; | |
10 | }⏎ |
0 | /* | |
1 | * Java2DWrapper.java | |
2 | * | |
3 | * Allows transparent usage of JTS Geometry classes via PostgreSQL JDBC driver | |
4 | * connected to a PostGIS enabled PostgreSQL server. | |
5 | * | |
6 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
7 | * | |
8 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public | |
21 | * License along with this library; if not, write to the Free Software | |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
23 | * | |
24 | */ | |
25 | ||
26 | package net.postgis.jdbc.java2d; | |
27 | ||
28 | import org.postgresql.Driver; | |
29 | import org.postgresql.PGConnection; | |
30 | ||
31 | import java.sql.Connection; | |
32 | import java.sql.SQLException; | |
33 | import java.util.Properties; | |
34 | import java.util.logging.Logger; | |
35 | ||
36 | /** | |
37 | * Java2DWrapper | |
38 | * | |
39 | * Wraps the PostGreSQL Driver to add transparent readonly support for PostGIS | |
40 | * objects into java2d path objects. | |
41 | * | |
42 | * This method currently works with J2EE DataSource implementations, and with | |
43 | * DriverManager framework. | |
44 | * | |
45 | * Simply replace the "jdbc:postgresql:" with a "jdbc:postgis_j2d" in the | |
46 | * jdbc URL. | |
47 | * | |
48 | * @author markus.schaber@logix-tt.com | |
49 | * | |
50 | */ | |
51 | public class Java2DWrapper extends Driver { | |
52 | ||
53 | private static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; | |
54 | public static final String POSTGIS_PROTOCOL = "jdbc:postgis_j2d:"; | |
55 | public static final String REVISION = "$Revision$"; | |
56 | ||
57 | public Java2DWrapper() { | |
58 | super(); | |
59 | } | |
60 | ||
61 | static { | |
62 | try { | |
63 | // Analogy to org.postgresql.Driver | |
64 | java.sql.DriverManager.registerDriver(new Java2DWrapper()); | |
65 | } catch (SQLException e) { | |
66 | e.printStackTrace(); | |
67 | } | |
68 | } | |
69 | ||
70 | /** | |
71 | * Creates a postgresql connection, and then adds the PostGIS data types to | |
72 | * it calling addpgtypes() | |
73 | * | |
74 | * @param url the URL of the database to connect to | |
75 | * @param info a list of arbitrary tag/value pairs as connection arguments | |
76 | * @return a connection to the URL or null if it isnt us | |
77 | * @exception SQLException if a database access error occurs | |
78 | * | |
79 | * @see java.sql.Driver#connect | |
80 | * @see org.postgresql.Driver | |
81 | */ | |
82 | public java.sql.Connection connect(String url, Properties info) throws SQLException { | |
83 | url = mangleURL(url); | |
84 | Connection result = super.connect(url, info); | |
85 | addGISTypes((PGConnection) result); | |
86 | return result; | |
87 | } | |
88 | ||
89 | ||
90 | /** | |
91 | * Adds the JTS/PostGIS Data types to a PG Connection. | |
92 | * | |
93 | * @throws SQLException when a SQLException occurs | |
94 | * @param pgconn The PGConnection object to add the types to | |
95 | * @throws SQLException when an SQLException occurs | |
96 | */ | |
97 | public static void addGISTypes(PGConnection pgconn) throws SQLException { | |
98 | pgconn.addDataType("geometry", PGShapeGeometry.class); | |
99 | pgconn.addDataType("box3d", net.postgis.jdbc.PGbox3d.class); | |
100 | pgconn.addDataType("box2d", net.postgis.jdbc.PGbox2d.class); | |
101 | } | |
102 | ||
103 | ||
104 | /** | |
105 | * Mangles the PostGIS URL to return the original PostGreSQL URL | |
106 | * | |
107 | * @param url String containing the url to be "mangled" | |
108 | * @return "mangled" string | |
109 | * @throws SQLException when a SQLException occurs | |
110 | */ | |
111 | public static String mangleURL(String url) throws SQLException { | |
112 | if (url.startsWith(POSTGIS_PROTOCOL)) { | |
113 | return POSTGRES_PROTOCOL + url.substring(POSTGIS_PROTOCOL.length()); | |
114 | } else { | |
115 | throw new SQLException("Unknown protocol or subprotocol in url " + url); | |
116 | } | |
117 | } | |
118 | ||
119 | /** | |
120 | * Returns true if the driver thinks it can open a connection to the given | |
121 | * URL. Typically, drivers will return true if they understand the | |
122 | * subprotocol specified in the URL and false if they don't. Our protocols | |
123 | * start with jdbc:postgresql_postGIS: | |
124 | * | |
125 | * @see java.sql.Driver#acceptsURL | |
126 | * @param url the URL of the driver | |
127 | * @return true if this driver accepts the given URL | |
128 | */ | |
129 | public boolean acceptsURL(String url) { | |
130 | try { | |
131 | url = mangleURL(url); | |
132 | } catch (SQLException e) { | |
133 | return false; | |
134 | } | |
135 | return super.acceptsURL(url); | |
136 | } | |
137 | ||
138 | /** | |
139 | * Gets the underlying drivers major version number | |
140 | * | |
141 | * @return the drivers major version number | |
142 | */ | |
143 | public int getMajorVersion() { | |
144 | return super.getMajorVersion(); | |
145 | } | |
146 | ||
147 | /** | |
148 | * Get the underlying drivers minor version number | |
149 | * | |
150 | * @return the drivers minor version number | |
151 | */ | |
152 | public int getMinorVersion() { | |
153 | return super.getMinorVersion(); | |
154 | } | |
155 | ||
156 | ||
157 | /** | |
158 | * Returns our own CVS version plus postgres Version | |
159 | * | |
160 | * @return String identifier for the version | |
161 | */ | |
162 | public static String getVersion() { | |
163 | return "Java2DWrapper " + REVISION + ", wrapping " + Driver.getVersion(); | |
164 | } | |
165 | ||
166 | public Logger getParentLogger() { | |
167 | throw new UnsupportedOperationException("Not supported yet."); | |
168 | } | |
169 | } |
0 | /* | |
1 | * PGShapeGeometry.java | |
2 | * | |
3 | * Allows PostGIS data to be read directly into a java2d shape | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package net.postgis.jdbc.java2d; | |
26 | ||
27 | import java.awt.Rectangle; | |
28 | import java.awt.Shape; | |
29 | import java.awt.geom.*; | |
30 | import java.sql.SQLException; | |
31 | ||
32 | import org.postgresql.util.PGobject; | |
33 | ||
34 | /** | |
35 | * PostGIS Java2D geometry implementation (read-only). | |
36 | * | |
37 | * Supports PostGIS 1.x (lwgeom hexwkb). | |
38 | * | |
39 | * As the java.awt.Shape methods currently are implemented by using a | |
40 | * java.awt.geom.GeneralPath object, they have the same semantics. | |
41 | * | |
42 | * NOTE: (Multi)Points are translated into a sequence of single MoveTo and LineTo | |
43 | * commands, but WITHOUT a closePath command. When rendering with a stroke that | |
44 | * is not solid, the points may not be rendered. | |
45 | * | |
46 | * (Multi)LineStrings are translated into a sequence of a single MoveTo and | |
47 | * multiple LineTo vertices, and Polygon rings into a sequence of a single | |
48 | * MoveTo, multiple LineTo and a closePath command. To allow correct Polygon | |
49 | * filling, our PathIterators have GeneralPath.WIND_EVEN_ODD as winding rule. | |
50 | * | |
51 | * @see java.awt.geom.GeneralPath | |
52 | * @see java.awt.Shape | |
53 | * @see org.postgresql.util.PGobject | |
54 | * | |
55 | * @author Markus Schaber | |
56 | */ | |
57 | ||
58 | public class PGShapeGeometry extends PGobject implements Shape { | |
59 | /* JDK 1.5 Serialization */ | |
60 | private static final long serialVersionUID = 0x100; | |
61 | ||
62 | final static ShapeBinaryParser parser = new ShapeBinaryParser(); | |
63 | ||
64 | private final GeneralPath path; | |
65 | ||
66 | private int srid; | |
67 | ||
68 | /** | |
69 | * Constructor called by JDBC drivers. call setValue afterwards to fill with | |
70 | * Geometry data. | |
71 | * | |
72 | */ | |
73 | public PGShapeGeometry() { | |
74 | setType("geometry"); | |
75 | path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); | |
76 | } | |
77 | ||
78 | ||
79 | /** | |
80 | * Construct directly from a General Path and SRID value | |
81 | * | |
82 | * @param path GeneralPath to be used | |
83 | * @param srid SRID value to be used | |
84 | */ | |
85 | public PGShapeGeometry(GeneralPath path, int srid) { | |
86 | setType("geometry"); | |
87 | this.path = path; | |
88 | this.srid = srid; | |
89 | } | |
90 | ||
91 | ||
92 | /** | |
93 | * Construct with HexWKB representation | |
94 | * | |
95 | * @param value String representation of the HexWKB data | |
96 | * @throws SQLException when a SQLException occurs | |
97 | */ | |
98 | public PGShapeGeometry(String value) throws SQLException { | |
99 | this(); | |
100 | setValue(value); | |
101 | } | |
102 | ||
103 | /** | |
104 | * Reads the HexWKB representation - to be called by the jdbc drivers. Be | |
105 | * shure to call this only once and if you used the PGShapeGeometry() | |
106 | * constructor without parameters. In all other cases, behaviour is | |
107 | * undefined. | |
108 | */ | |
109 | public void setValue(String value) throws SQLException { | |
110 | srid = parser.parse(value, path); | |
111 | } | |
112 | ||
113 | public String toString() { | |
114 | return "PGShapeGeometry " + path.toString(); | |
115 | } | |
116 | ||
117 | /** We currently have read-only support, so this method returns null */ | |
118 | public String getValue() { | |
119 | return null; | |
120 | } | |
121 | ||
122 | public boolean equals(Object obj) { | |
123 | if (obj instanceof PGShapeGeometry) | |
124 | return ((PGShapeGeometry) obj).path.equals(path); | |
125 | return false; | |
126 | } | |
127 | ||
128 | ||
129 | /** | |
130 | * Return the SRID or Geometry.UNKNOWN_SRID if none was available | |
131 | * @return the SRID value to be used | |
132 | */ | |
133 | public int getSRID() { | |
134 | return srid; | |
135 | } | |
136 | ||
137 | // following are the java2d Shape method implementations... | |
138 | public boolean contains(double x, double y) { | |
139 | return path.contains(x, y); | |
140 | } | |
141 | ||
142 | public boolean contains(double x, double y, double w, double h) { | |
143 | return path.contains(x, y, w, h); | |
144 | } | |
145 | ||
146 | public boolean intersects(double x, double y, double w, double h) { | |
147 | return path.intersects(x, y, w, h); | |
148 | } | |
149 | ||
150 | public Rectangle getBounds() { | |
151 | return path.getBounds(); | |
152 | } | |
153 | ||
154 | public boolean contains(Point2D p) { | |
155 | return path.contains(p); | |
156 | } | |
157 | ||
158 | public Rectangle2D getBounds2D() { | |
159 | return path.getBounds2D(); | |
160 | } | |
161 | ||
162 | public boolean contains(Rectangle2D r) { | |
163 | return path.contains(r); | |
164 | } | |
165 | ||
166 | public boolean intersects(Rectangle2D r) { | |
167 | return path.intersects(r); | |
168 | } | |
169 | ||
170 | public PathIterator getPathIterator(AffineTransform at) { | |
171 | return path.getPathIterator(at); | |
172 | } | |
173 | ||
174 | public PathIterator getPathIterator(AffineTransform at, double flatness) { | |
175 | return path.getPathIterator(at, flatness); | |
176 | } | |
177 | } |
0 | /* | |
1 | * ShapeBinaryParser.java | |
2 | * | |
3 | * Shape Binary Parser for Java2D - relies on net.postgis V1.0.0+ package. | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | package net.postgis.jdbc.java2d; | |
25 | ||
26 | import java.awt.geom.GeneralPath; | |
27 | ||
28 | import net.postgis.jdbc.geometry.Geometry; | |
29 | import net.postgis.jdbc.geometry.binary.ByteGetter; | |
30 | import net.postgis.jdbc.geometry.binary.ValueGetter; | |
31 | import net.postgis.jdbc.geometry.binary.ByteGetter.BinaryByteGetter; | |
32 | import net.postgis.jdbc.geometry.binary.ByteGetter.StringByteGetter; | |
33 | ||
34 | /** | |
35 | * Parse binary representation of geometries. Currently, only text rep (hexed) | |
36 | * implementation is tested. | |
37 | * | |
38 | * It should be easy to add char[] and CharSequence ByteGetter instances, | |
39 | * although the latter one is not compatible with older jdks. | |
40 | * | |
41 | * I did not implement real unsigned 32-bit integers or emulate them with long, | |
42 | * as both java Arrays and Strings currently can have only 2^31-1 elements | |
43 | * (bytes), so we cannot even get or build Geometries with more than approx. | |
44 | * 2^28 coordinates (8 bytes each). | |
45 | * | |
46 | * @author Markus Schaber, markus.schaber@logix-tt.com | |
47 | * | |
48 | */ | |
49 | public class ShapeBinaryParser { | |
50 | ||
51 | /** | |
52 | * Get the appropriate ValueGetter for my endianness | |
53 | * | |
54 | * @param bytes The appropriate Byte Getter | |
55 | * | |
56 | * @return the ValueGetter | |
57 | */ | |
58 | public static ValueGetter valueGetterForEndian(ByteGetter bytes) { | |
59 | if (bytes.get(0) == ValueGetter.XDR.NUMBER) { // XDR | |
60 | return new ValueGetter.XDR(bytes); | |
61 | } else if (bytes.get(0) == ValueGetter.NDR.NUMBER) { | |
62 | return new ValueGetter.NDR(bytes); | |
63 | } else { | |
64 | throw new IllegalArgumentException("Unknown Endian type:" + bytes.get(0)); | |
65 | } | |
66 | } | |
67 | ||
68 | /** | |
69 | * Parse a hex encoded geometry | |
70 | * | |
71 | * Is synchronized to protect offset counter. (Unfortunately, Java does not | |
72 | * have neither call by reference nor multiple return values.) | |
73 | * | |
74 | * @param value String representation of the value to be parsed | |
75 | * @param path GeneralPath to provide the parsed value to | |
76 | * | |
77 | * @return a potential SRID or Geometry.UNKNOWN_SRID if not present | |
78 | */ | |
79 | public synchronized int parse(String value, GeneralPath path) { | |
80 | StringByteGetter bytes = new ByteGetter.StringByteGetter(value); | |
81 | return parseGeometry(valueGetterForEndian(bytes), path); | |
82 | } | |
83 | ||
84 | /** | |
85 | * Parse a binary encoded geometry. | |
86 | * | |
87 | * Is synchronized to protect offset counter. (Unfortunately, Java does not | |
88 | * have neither call by reference nor multiple return values.) | |
89 | * | |
90 | * @param value byte array representation of the value to be parsed | |
91 | * @param path GeneralPath to provide the parsed value to | |
92 | * | |
93 | * @return a potential SRID or Geometry.UNKNOWN_SRID if not present | |
94 | */ | |
95 | public synchronized int parse(byte[] value, GeneralPath path) { | |
96 | BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value); | |
97 | return parseGeometry(valueGetterForEndian(bytes), path); | |
98 | } | |
99 | ||
100 | /** | |
101 | * Parse a geometry starting at offset. | |
102 | * | |
103 | * @param data ValueGetter containing the value to be parsed | |
104 | * @param path GeneralPath to provide the parsed value to | |
105 | * | |
106 | * @return a potential SRID or Geometry.UNKNOWN_SRID if not present | |
107 | */ | |
108 | protected int parseGeometry(ValueGetter data, GeneralPath path) { | |
109 | byte endian = data.getByte(); // skip and test endian flag | |
110 | if (endian != data.endian) { | |
111 | throw new IllegalArgumentException("Endian inconsistency!"); | |
112 | } | |
113 | int typeword = data.getInt(); | |
114 | ||
115 | int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits | |
116 | ||
117 | boolean haveZ = (typeword & 0x80000000) != 0; | |
118 | boolean haveM = (typeword & 0x40000000) != 0; | |
119 | boolean haveS = (typeword & 0x20000000) != 0; | |
120 | ||
121 | int srid = Geometry.UNKNOWN_SRID; | |
122 | ||
123 | if (haveS) { | |
124 | srid = Geometry.parseSRID(data.getInt()); | |
125 | } | |
126 | ||
127 | switch (realtype) { | |
128 | case net.postgis.jdbc.geometry.Geometry.POINT : | |
129 | parsePoint(data, haveZ, haveM, path); | |
130 | break; | |
131 | case net.postgis.jdbc.geometry.Geometry.LINESTRING : | |
132 | parseLineString(data, haveZ, haveM, path); | |
133 | break; | |
134 | case net.postgis.jdbc.geometry.Geometry.POLYGON : | |
135 | parsePolygon(data, haveZ, haveM, path); | |
136 | break; | |
137 | case net.postgis.jdbc.geometry.Geometry.MULTIPOINT : | |
138 | parseMultiPoint(data, path); | |
139 | break; | |
140 | case net.postgis.jdbc.geometry.Geometry.MULTILINESTRING : | |
141 | parseMultiLineString(data, path); | |
142 | break; | |
143 | case net.postgis.jdbc.geometry.Geometry.MULTIPOLYGON : | |
144 | parseMultiPolygon(data, path); | |
145 | break; | |
146 | case net.postgis.jdbc.geometry.Geometry.GEOMETRYCOLLECTION : | |
147 | parseCollection(data, path); | |
148 | break; | |
149 | default : | |
150 | throw new IllegalArgumentException("Unknown Geometry Type!"); | |
151 | } | |
152 | return srid; | |
153 | } | |
154 | ||
155 | private void parsePoint(ValueGetter data, boolean haveZ, boolean haveM, GeneralPath path) { | |
156 | double x = data.getDouble(); | |
157 | double y = data.getDouble(); | |
158 | path.moveTo(x, y); | |
159 | path.lineTo(x, y); | |
160 | skipZM(data, haveZ, haveM); | |
161 | } | |
162 | ||
163 | private void skipZM(ValueGetter data, boolean haveZ, boolean haveM) { | |
164 | if (haveZ) { // skip Z value | |
165 | data.getDouble(); | |
166 | } | |
167 | if (haveM) { // skip M value | |
168 | data.getDouble(); | |
169 | } | |
170 | } | |
171 | ||
172 | /** Parse an Array of "full" Geometries */ | |
173 | private void parseGeometryArray(ValueGetter data, int count, GeneralPath path) { | |
174 | for (int i = 0; i < count; i++) { | |
175 | parseGeometry(data, path); | |
176 | } | |
177 | } | |
178 | ||
179 | /** | |
180 | * Parse an Array of "slim" Points (without endianness and type, part of | |
181 | * LinearRing and Linestring, but not MultiPoint! | |
182 | * | |
183 | * @param data ValueGetter containing the value to be parsed | |
184 | * @param haveZ flag indicating if Z values exist | |
185 | * @param haveM flag indicating if M values exist | |
186 | * @param path GeneralPath to provide the parsed value to | |
187 | */ | |
188 | private void parseCS(ValueGetter data, boolean haveZ, boolean haveM, GeneralPath path) { | |
189 | int count = data.getInt(); | |
190 | if (count > 0) { | |
191 | path.moveTo((float) data.getDouble(), (float) data.getDouble()); | |
192 | skipZM(data, haveZ, haveM); | |
193 | for (int i = 1; i < count; i++) { | |
194 | path.lineTo((float) data.getDouble(), (float) data.getDouble()); | |
195 | skipZM(data, haveZ, haveM); | |
196 | } | |
197 | } | |
198 | } | |
199 | ||
200 | ||
201 | private void parseMultiPoint(ValueGetter data, GeneralPath path) { | |
202 | parseGeometryArray(data, data.getInt(), path); | |
203 | } | |
204 | ||
205 | private void parseLineString(ValueGetter data, boolean haveZ, boolean haveM, GeneralPath path) { | |
206 | parseCS(data, haveZ, haveM, path); | |
207 | } | |
208 | ||
209 | private void parseLinearRing(ValueGetter data, boolean haveZ, boolean haveM, GeneralPath path) { | |
210 | parseCS(data, haveZ, haveM, path); | |
211 | path.closePath(); | |
212 | } | |
213 | ||
214 | private void parsePolygon(ValueGetter data, boolean haveZ, boolean haveM, GeneralPath path) { | |
215 | int holecount = data.getInt() - 1; | |
216 | // parse shell | |
217 | parseLinearRing(data, haveZ, haveM, path); | |
218 | // parse inner rings | |
219 | for (int i = 0; i < holecount; i++) { | |
220 | parseLinearRing(data, haveZ, haveM, path); | |
221 | } | |
222 | } | |
223 | ||
224 | private void parseMultiLineString(ValueGetter data, GeneralPath path) { | |
225 | int count = data.getInt(); | |
226 | parseGeometryArray(data, count, path); | |
227 | } | |
228 | ||
229 | private void parseMultiPolygon(ValueGetter data, GeneralPath path) { | |
230 | int count = data.getInt(); | |
231 | parseGeometryArray(data, count, path); | |
232 | } | |
233 | ||
234 | private void parseCollection(ValueGetter data, GeneralPath path) { | |
235 | int count = data.getInt(); | |
236 | parseGeometryArray(data, count, path); | |
237 | } | |
238 | } |
0 | /* | |
1 | * Java2DWrapper.java | |
2 | * | |
3 | * Allows transparent usage of JTS Geometry classes via PostgreSQL JDBC driver | |
4 | * connected to a PostGIS enabled PostgreSQL server. | |
5 | * | |
6 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
7 | * | |
8 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public | |
21 | * License along with this library; if not, write to the Free Software | |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
23 | * | |
24 | */ | |
25 | ||
26 | package org.postgis.java2d; | |
27 | ||
28 | import org.postgresql.Driver; | |
29 | import org.postgresql.PGConnection; | |
30 | ||
31 | import java.sql.Connection; | |
32 | import java.sql.SQLException; | |
33 | import java.sql.SQLFeatureNotSupportedException; | |
34 | import java.util.Properties; | |
35 | import java.util.logging.Logger; | |
36 | ||
37 | /** | |
38 | * Java2DWrapper | |
39 | * | |
40 | * Wraps the PostGreSQL Driver to add transparent readonly support for PostGIS | |
41 | * objects into java2d path objects. | |
42 | * | |
43 | * This method currently works with J2EE DataSource implementations, and with | |
44 | * DriverManager framework. | |
45 | * | |
46 | * Simply replace the "jdbc:postgresql:" with a "jdbc:postgis_j2d" in the | |
47 | * jdbc URL. | |
48 | * | |
49 | * @author markus.schaber@logix-tt.com | |
50 | * | |
51 | */ | |
52 | public class Java2DWrapper extends Driver { | |
53 | ||
54 | private static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; | |
55 | public static final String POSTGIS_PROTOCOL = "jdbc:postgis_j2d:"; | |
56 | public static final String REVISION = "$Revision$"; | |
57 | ||
58 | public Java2DWrapper() { | |
59 | super(); | |
60 | } | |
61 | ||
62 | static { | |
63 | try { | |
64 | // Analogy to org.postgresql.Driver | |
65 | java.sql.DriverManager.registerDriver(new Java2DWrapper()); | |
66 | } catch (SQLException e) { | |
67 | e.printStackTrace(); | |
68 | } | |
69 | } | |
70 | ||
71 | /** | |
72 | * Creates a postgresql connection, and then adds the PostGIS data types to | |
73 | * it calling addpgtypes() | |
74 | * | |
75 | * @param url the URL of the database to connect to | |
76 | * @param info a list of arbitrary tag/value pairs as connection arguments | |
77 | * @return a connection to the URL or null if it isnt us | |
78 | * @exception SQLException if a database access error occurs | |
79 | * | |
80 | * @see java.sql.Driver#connect | |
81 | * @see org.postgresql.Driver | |
82 | */ | |
83 | public java.sql.Connection connect(String url, Properties info) throws SQLException { | |
84 | url = mangleURL(url); | |
85 | Connection result = super.connect(url, info); | |
86 | addGISTypes((PGConnection) result); | |
87 | return result; | |
88 | } | |
89 | ||
90 | ||
91 | /** | |
92 | * Adds the JTS/PostGIS Data types to a PG Connection. | |
93 | * | |
94 | * @throws SQLException when a SQLException occurs | |
95 | * @param pgconn The PGConnection object to add the types to | |
96 | * @throws SQLException when an SQLException occurs | |
97 | */ | |
98 | public static void addGISTypes(PGConnection pgconn) throws SQLException { | |
99 | pgconn.addDataType("geometry", PGShapeGeometry.class); | |
100 | pgconn.addDataType("box3d", org.postgis.PGbox3d.class); | |
101 | pgconn.addDataType("box2d", org.postgis.PGbox2d.class); | |
102 | } | |
103 | ||
104 | ||
105 | /** | |
106 | * Mangles the PostGIS URL to return the original PostGreSQL URL | |
107 | * | |
108 | * @param url String containing the url to be "mangled" | |
109 | * @return "mangled" string | |
110 | * @throws SQLException when a SQLException occurs | |
111 | */ | |
112 | public static String mangleURL(String url) throws SQLException { | |
113 | if (url.startsWith(POSTGIS_PROTOCOL)) { | |
114 | return POSTGRES_PROTOCOL + url.substring(POSTGIS_PROTOCOL.length()); | |
115 | } else { | |
116 | throw new SQLException("Unknown protocol or subprotocol in url " + url); | |
117 | } | |
118 | } | |
119 | ||
120 | /** | |
121 | * Returns true if the driver thinks it can open a connection to the given | |
122 | * URL. Typically, drivers will return true if they understand the | |
123 | * subprotocol specified in the URL and false if they don't. Our protocols | |
124 | * start with jdbc:postgresql_postGIS: | |
125 | * | |
126 | * @see java.sql.Driver#acceptsURL | |
127 | * @param url the URL of the driver | |
128 | * @return true if this driver accepts the given URL | |
129 | */ | |
130 | public boolean acceptsURL(String url) { | |
131 | try { | |
132 | url = mangleURL(url); | |
133 | } catch (SQLException e) { | |
134 | return false; | |
135 | } | |
136 | return super.acceptsURL(url); | |
137 | } | |
138 | ||
139 | /** | |
140 | * Gets the underlying drivers major version number | |
141 | * | |
142 | * @return the drivers major version number | |
143 | */ | |
144 | public int getMajorVersion() { | |
145 | return super.getMajorVersion(); | |
146 | } | |
147 | ||
148 | /** | |
149 | * Get the underlying drivers minor version number | |
150 | * | |
151 | * @return the drivers minor version number | |
152 | */ | |
153 | public int getMinorVersion() { | |
154 | return super.getMinorVersion(); | |
155 | } | |
156 | ||
157 | ||
158 | /** | |
159 | * Returns our own CVS version plus postgres Version | |
160 | * | |
161 | * @return String identifier for the version | |
162 | */ | |
163 | public static String getVersion() { | |
164 | return "Java2DWrapper " + REVISION + ", wrapping " + Driver.getVersion(); | |
165 | } | |
166 | ||
167 | public Logger getParentLogger() { | |
168 | throw new UnsupportedOperationException("Not supported yet."); | |
169 | } | |
170 | } |
0 | /* | |
1 | * PGShapeGeometry.java | |
2 | * | |
3 | * Allows PostGIS data to be read directly into a java2d shape | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package org.postgis.java2d; | |
26 | ||
27 | import java.awt.Rectangle; | |
28 | import java.awt.Shape; | |
29 | import java.awt.geom.*; | |
30 | import java.sql.SQLException; | |
31 | ||
32 | import org.postgresql.util.PGobject; | |
33 | ||
34 | /** | |
35 | * PostGIS Java2D geometry implementation (read-only). | |
36 | * | |
37 | * Supports PostGIS 1.x (lwgeom hexwkb). | |
38 | * | |
39 | * As the java.awt.Shape methods currently are implemented by using a | |
40 | * java.awt.geom.GeneralPath object, they have the same semantics. | |
41 | * | |
42 | * NOTE: (Multi)Points are translated into a sequence of single MoveTo and LineTo | |
43 | * commands, but WITHOUT a closePath command. When rendering with a stroke that | |
44 | * is not solid, the points may not be rendered. | |
45 | * | |
46 | * (Multi)LineStrings are translated into a sequence of a single MoveTo and | |
47 | * multiple LineTo vertices, and Polygon rings into a sequence of a single | |
48 | * MoveTo, multiple LineTo and a closePath command. To allow correct Polygon | |
49 | * filling, our PathIterators have GeneralPath.WIND_EVEN_ODD as winding rule. | |
50 | * | |
51 | * @see java.awt.geom.GeneralPath | |
52 | * @see java.awt.Shape | |
53 | * @see org.postgresql.util.PGobject | |
54 | * | |
55 | * @author Markus Schaber | |
56 | */ | |
57 | ||
58 | public class PGShapeGeometry extends PGobject implements Shape { | |
59 | /* JDK 1.5 Serialization */ | |
60 | private static final long serialVersionUID = 0x100; | |
61 | ||
62 | final static ShapeBinaryParser parser = new ShapeBinaryParser(); | |
63 | ||
64 | private final GeneralPath path; | |
65 | ||
66 | private int srid; | |
67 | ||
68 | /** | |
69 | * Constructor called by JDBC drivers. call setValue afterwards to fill with | |
70 | * Geometry data. | |
71 | * | |
72 | */ | |
73 | public PGShapeGeometry() { | |
74 | setType("geometry"); | |
75 | path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); | |
76 | } | |
77 | ||
78 | ||
79 | /** | |
80 | * Construct directly from a General Path and SRID value | |
81 | * | |
82 | * @param path GeneralPath to be used | |
83 | * @param srid SRID value to be used | |
84 | */ | |
85 | public PGShapeGeometry(GeneralPath path, int srid) { | |
86 | setType("geometry"); | |
87 | this.path = path; | |
88 | this.srid = srid; | |
89 | } | |
90 | ||
91 | ||
92 | /** | |
93 | * Construct with HexWKB representation | |
94 | * | |
95 | * @param value String representation of the HexWKB data | |
96 | * @throws SQLException when a SQLException occurs | |
97 | */ | |
98 | public PGShapeGeometry(String value) throws SQLException { | |
99 | this(); | |
100 | setValue(value); | |
101 | } | |
102 | ||
103 | /** | |
104 | * Reads the HexWKB representation - to be called by the jdbc drivers. Be | |
105 | * shure to call this only once and if you used the PGShapeGeometry() | |
106 | * constructor without parameters. In all other cases, behaviour is | |
107 | * undefined. | |
108 | */ | |
109 | public void setValue(String value) throws SQLException { | |
110 | srid = parser.parse(value, path); | |
111 | } | |
112 | ||
113 | public String toString() { | |
114 | return "PGShapeGeometry " + path.toString(); | |
115 | } | |
116 | ||
117 | /** We currently have read-only support, so this method returns null */ | |
118 | public String getValue() { | |
119 | return null; | |
120 | } | |
121 | ||
122 | public boolean equals(Object obj) { | |
123 | if (obj instanceof PGShapeGeometry) | |
124 | return ((PGShapeGeometry) obj).path.equals(path); | |
125 | return false; | |
126 | } | |
127 | ||
128 | ||
129 | /** | |
130 | * Return the SRID or Geometry.UNKNOWN_SRID if none was available | |
131 | * @return the SRID value to be used | |
132 | */ | |
133 | public int getSRID() { | |
134 | return srid; | |
135 | } | |
136 | ||
137 | // following are the java2d Shape method implementations... | |
138 | public boolean contains(double x, double y) { | |
139 | return path.contains(x, y); | |
140 | } | |
141 | ||
142 | public boolean contains(double x, double y, double w, double h) { | |
143 | return path.contains(x, y, w, h); | |
144 | } | |
145 | ||
146 | public boolean intersects(double x, double y, double w, double h) { | |
147 | return path.intersects(x, y, w, h); | |
148 | } | |
149 | ||
150 | public Rectangle getBounds() { | |
151 | return path.getBounds(); | |
152 | } | |
153 | ||
154 | public boolean contains(Point2D p) { | |
155 | return path.contains(p); | |
156 | } | |
157 | ||
158 | public Rectangle2D getBounds2D() { | |
159 | return path.getBounds2D(); | |
160 | } | |
161 | ||
162 | public boolean contains(Rectangle2D r) { | |
163 | return path.contains(r); | |
164 | } | |
165 | ||
166 | public boolean intersects(Rectangle2D r) { | |
167 | return path.intersects(r); | |
168 | } | |
169 | ||
170 | public PathIterator getPathIterator(AffineTransform at) { | |
171 | return path.getPathIterator(at); | |
172 | } | |
173 | ||
174 | public PathIterator getPathIterator(AffineTransform at, double flatness) { | |
175 | return path.getPathIterator(at, flatness); | |
176 | } | |
177 | } |
0 | /* | |
1 | * ShapeBinaryParser.java | |
2 | * | |
3 | * Shape Binary Parser for Java2D - relies on org.postgis V1.0.0+ package. | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | package org.postgis.java2d; | |
25 | ||
26 | import java.awt.geom.GeneralPath; | |
27 | ||
28 | import org.postgis.Geometry; | |
29 | import org.postgis.binary.ByteGetter; | |
30 | import org.postgis.binary.ValueGetter; | |
31 | import org.postgis.binary.ByteGetter.BinaryByteGetter; | |
32 | import org.postgis.binary.ByteGetter.StringByteGetter; | |
33 | ||
34 | /** | |
35 | * Parse binary representation of geometries. Currently, only text rep (hexed) | |
36 | * implementation is tested. | |
37 | * | |
38 | * It should be easy to add char[] and CharSequence ByteGetter instances, | |
39 | * although the latter one is not compatible with older jdks. | |
40 | * | |
41 | * I did not implement real unsigned 32-bit integers or emulate them with long, | |
42 | * as both java Arrays and Strings currently can have only 2^31-1 elements | |
43 | * (bytes), so we cannot even get or build Geometries with more than approx. | |
44 | * 2^28 coordinates (8 bytes each). | |
45 | * | |
46 | * @author Markus Schaber, markus.schaber@logix-tt.com | |
47 | * | |
48 | */ | |
49 | public class ShapeBinaryParser { | |
50 | ||
51 | /** | |
52 | * Get the appropriate ValueGetter for my endianness | |
53 | * | |
54 | * @param bytes The appropriate Byte Getter | |
55 | * | |
56 | * @return the ValueGetter | |
57 | */ | |
58 | public static ValueGetter valueGetterForEndian(ByteGetter bytes) { | |
59 | if (bytes.get(0) == ValueGetter.XDR.NUMBER) { // XDR | |
60 | return new ValueGetter.XDR(bytes); | |
61 | } else if (bytes.get(0) == ValueGetter.NDR.NUMBER) { | |
62 | return new ValueGetter.NDR(bytes); | |
63 | } else { | |
64 | throw new IllegalArgumentException("Unknown Endian type:" + bytes.get(0)); | |
65 | } | |
66 | } | |
67 | ||
68 | /** | |
69 | * Parse a hex encoded geometry | |
70 | * | |
71 | * Is synchronized to protect offset counter. (Unfortunately, Java does not | |
72 | * have neither call by reference nor multiple return values.) | |
73 | * | |
74 | * @param value String representation of the value to be parsed | |
75 | * @param path GeneralPath to provide the parsed value to | |
76 | * | |
77 | * @return a potential SRID or Geometry.UNKNOWN_SRID if not present | |
78 | */ | |
79 | public synchronized int parse(String value, GeneralPath path) { | |
80 | StringByteGetter bytes = new ByteGetter.StringByteGetter(value); | |
81 | return parseGeometry(valueGetterForEndian(bytes), path); | |
82 | } | |
83 | ||
84 | /** | |
85 | * Parse a binary encoded geometry. | |
86 | * | |
87 | * Is synchronized to protect offset counter. (Unfortunately, Java does not | |
88 | * have neither call by reference nor multiple return values.) | |
89 | * | |
90 | * @param value byte array representation of the value to be parsed | |
91 | * @param path GeneralPath to provide the parsed value to | |
92 | * | |
93 | * @return a potential SRID or Geometry.UNKNOWN_SRID if not present | |
94 | */ | |
95 | public synchronized int parse(byte[] value, GeneralPath path) { | |
96 | BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value); | |
97 | return parseGeometry(valueGetterForEndian(bytes), path); | |
98 | } | |
99 | ||
100 | /** | |
101 | * Parse a geometry starting at offset. | |
102 | * | |
103 | * @param data ValueGetter containing the value to be parsed | |
104 | * @param path GeneralPath to provide the parsed value to | |
105 | * | |
106 | * @return a potential SRID or Geometry.UNKNOWN_SRID if not present | |
107 | */ | |
108 | protected int parseGeometry(ValueGetter data, GeneralPath path) { | |
109 | byte endian = data.getByte(); // skip and test endian flag | |
110 | if (endian != data.endian) { | |
111 | throw new IllegalArgumentException("Endian inconsistency!"); | |
112 | } | |
113 | int typeword = data.getInt(); | |
114 | ||
115 | int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits | |
116 | ||
117 | boolean haveZ = (typeword & 0x80000000) != 0; | |
118 | boolean haveM = (typeword & 0x40000000) != 0; | |
119 | boolean haveS = (typeword & 0x20000000) != 0; | |
120 | ||
121 | int srid = Geometry.UNKNOWN_SRID; | |
122 | ||
123 | if (haveS) { | |
124 | srid = Geometry.parseSRID(data.getInt()); | |
125 | } | |
126 | ||
127 | switch (realtype) { | |
128 | case org.postgis.Geometry.POINT : | |
129 | parsePoint(data, haveZ, haveM, path); | |
130 | break; | |
131 | case org.postgis.Geometry.LINESTRING : | |
132 | parseLineString(data, haveZ, haveM, path); | |
133 | break; | |
134 | case org.postgis.Geometry.POLYGON : | |
135 | parsePolygon(data, haveZ, haveM, path); | |
136 | break; | |
137 | case org.postgis.Geometry.MULTIPOINT : | |
138 | parseMultiPoint(data, path); | |
139 | break; | |
140 | case org.postgis.Geometry.MULTILINESTRING : | |
141 | parseMultiLineString(data, path); | |
142 | break; | |
143 | case org.postgis.Geometry.MULTIPOLYGON : | |
144 | parseMultiPolygon(data, path); | |
145 | break; | |
146 | case org.postgis.Geometry.GEOMETRYCOLLECTION : | |
147 | parseCollection(data, path); | |
148 | break; | |
149 | default : | |
150 | throw new IllegalArgumentException("Unknown Geometry Type!"); | |
151 | } | |
152 | return srid; | |
153 | } | |
154 | ||
155 | private void parsePoint(ValueGetter data, boolean haveZ, boolean haveM, GeneralPath path) { | |
156 | double x = data.getDouble(); | |
157 | double y = data.getDouble(); | |
158 | path.moveTo(x, y); | |
159 | path.lineTo(x, y); | |
160 | skipZM(data, haveZ, haveM); | |
161 | } | |
162 | ||
163 | private void skipZM(ValueGetter data, boolean haveZ, boolean haveM) { | |
164 | if (haveZ) { // skip Z value | |
165 | data.getDouble(); | |
166 | } | |
167 | if (haveM) { // skip M value | |
168 | data.getDouble(); | |
169 | } | |
170 | } | |
171 | ||
172 | /** Parse an Array of "full" Geometries */ | |
173 | private void parseGeometryArray(ValueGetter data, int count, GeneralPath path) { | |
174 | for (int i = 0; i < count; i++) { | |
175 | parseGeometry(data, path); | |
176 | } | |
177 | } | |
178 | ||
179 | /** | |
180 | * Parse an Array of "slim" Points (without endianness and type, part of | |
181 | * LinearRing and Linestring, but not MultiPoint! | |
182 | * | |
183 | * @param data ValueGetter containing the value to be parsed | |
184 | * @param haveZ flag indicating if Z values exist | |
185 | * @param haveM flag indicating if M values exist | |
186 | * @param path GeneralPath to provide the parsed value to | |
187 | */ | |
188 | private void parseCS(ValueGetter data, boolean haveZ, boolean haveM, GeneralPath path) { | |
189 | int count = data.getInt(); | |
190 | if (count > 0) { | |
191 | path.moveTo((float) data.getDouble(), (float) data.getDouble()); | |
192 | skipZM(data, haveZ, haveM); | |
193 | for (int i = 1; i < count; i++) { | |
194 | path.lineTo((float) data.getDouble(), (float) data.getDouble()); | |
195 | skipZM(data, haveZ, haveM); | |
196 | } | |
197 | } | |
198 | } | |
199 | ||
200 | ||
201 | private void parseMultiPoint(ValueGetter data, GeneralPath path) { | |
202 | parseGeometryArray(data, data.getInt(), path); | |
203 | } | |
204 | ||
205 | private void parseLineString(ValueGetter data, boolean haveZ, boolean haveM, GeneralPath path) { | |
206 | parseCS(data, haveZ, haveM, path); | |
207 | } | |
208 | ||
209 | private void parseLinearRing(ValueGetter data, boolean haveZ, boolean haveM, GeneralPath path) { | |
210 | parseCS(data, haveZ, haveM, path); | |
211 | path.closePath(); | |
212 | } | |
213 | ||
214 | private void parsePolygon(ValueGetter data, boolean haveZ, boolean haveM, GeneralPath path) { | |
215 | int holecount = data.getInt() - 1; | |
216 | // parse shell | |
217 | parseLinearRing(data, haveZ, haveM, path); | |
218 | // parse inner rings | |
219 | for (int i = 0; i < holecount; i++) { | |
220 | parseLinearRing(data, haveZ, haveM, path); | |
221 | } | |
222 | } | |
223 | ||
224 | private void parseMultiLineString(ValueGetter data, GeneralPath path) { | |
225 | int count = data.getInt(); | |
226 | parseGeometryArray(data, count, path); | |
227 | } | |
228 | ||
229 | private void parseMultiPolygon(ValueGetter data, GeneralPath path) { | |
230 | int count = data.getInt(); | |
231 | parseGeometryArray(data, count, path); | |
232 | } | |
233 | ||
234 | private void parseCollection(ValueGetter data, GeneralPath path) { | |
235 | int count = data.getInt(); | |
236 | parseGeometryArray(data, count, path); | |
237 | } | |
238 | } |
+51
-0
0 | /* | |
1 | * SimpleJava2DWrapperTest.java | |
2 | * | |
3 | * SimpleJava2DWrapperTest for Java2D - relies on net.postgis V1.0.0+ package. | |
4 | * | |
5 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | * | |
21 | */ | |
22 | package net.postgis.jdbc.java2d; | |
23 | ||
24 | ||
25 | import org.slf4j.Logger; | |
26 | import org.slf4j.LoggerFactory; | |
27 | import org.testng.annotations.Test; | |
28 | ||
29 | ||
30 | /** | |
31 | * This class serves as little more than an initial placeholder for establishing test classes within | |
32 | * this module's test suite. | |
33 | * | |
34 | * @author Phillip Ross {@literal <phillip.w.g.ross@gmail.com>} | |
35 | */ | |
36 | public class SimpleJava2DWrapperTest { | |
37 | ||
38 | private static final Logger logger = LoggerFactory.getLogger(SimpleJava2DWrapperTest.class); | |
39 | ||
40 | private static final String JAVA2D_WRAPPER_CLASS_NAME = "net.postgis.jdbc.java2d.Java2DWrapper"; | |
41 | ||
42 | ||
43 | @Test | |
44 | public void testWrapperClassLoad() throws Exception { | |
45 | logger.debug("Loading java2d wrapper class: {}", JAVA2D_WRAPPER_CLASS_NAME); | |
46 | Class.forName(JAVA2D_WRAPPER_CLASS_NAME); | |
47 | } | |
48 | ||
49 | ||
50 | }⏎ |
0 | /* | |
1 | * SimpleJava2DWrapperTest.java | |
2 | * | |
3 | * SimpleJava2DWrapperTest for Java2D - relies on org.postgis V1.0.0+ package. | |
4 | * | |
5 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | * | |
21 | */ | |
22 | package org.postgis.java2d; | |
23 | ||
24 | ||
25 | import org.slf4j.Logger; | |
26 | import org.slf4j.LoggerFactory; | |
27 | import org.testng.annotations.Test; | |
28 | ||
29 | ||
30 | /** | |
31 | * This class serves as little more than an initial placeholder for establishing test classes within | |
32 | * this module's test suite. | |
33 | * | |
34 | * @author Phillip Ross {@literal <phillip.w.g.ross@gmail.com>} | |
35 | */ | |
36 | public class SimpleJava2DWrapperTest { | |
37 | ||
38 | private static final Logger logger = LoggerFactory.getLogger(SimpleJava2DWrapperTest.class); | |
39 | ||
40 | private static final String JAVA2D_WRAPPER_CLASS_NAME = "org.postgis.java2d.Java2DWrapper"; | |
41 | ||
42 | ||
43 | @Test | |
44 | public void testWrapperClassLoad() throws Exception { | |
45 | logger.debug("Loading java2d wrapper class: {}", JAVA2D_WRAPPER_CLASS_NAME); | |
46 | Class.forName(JAVA2D_WRAPPER_CLASS_NAME); | |
47 | } | |
48 | ||
49 | ||
50 | }⏎ |
9 | 9 | <appender-ref ref="STDOUT" /> |
10 | 10 | </root> |
11 | 11 | |
12 | <logger name="org.postgis.java2d" level="ERROR"/> | |
12 | <logger name="net.postgis.jdbc.java2d" level="ERROR"/> | |
13 | 13 | |
14 | 14 | </configuration>⏎ |
2 | 2 | |
3 | 3 | <test name="PostGIS JDBC Java2D Tests"> |
4 | 4 | <classes> |
5 | <class name="org.postgis.java2d.SimpleJava2DWrapperTest"/> | |
5 | <class name="net.postgis.jdbc.java2d.SimpleJava2DWrapperTest"/> | |
6 | 6 | </classes> |
7 | 7 | </test> |
8 | 8 |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
2 | <modelVersion>4.0.0</modelVersion> | |
3 | ||
4 | <parent> | |
5 | <groupId>net.postgis</groupId> | |
6 | <artifactId>postgis-java-aggregator</artifactId> | |
7 | <version>2021.1.0</version> | |
8 | </parent> | |
9 | ||
10 | <artifactId>postgis-jdbc-jts</artifactId> | |
11 | <version>2021.1.0</version> | |
12 | <packaging>jar</packaging> | |
13 | ||
14 | <name>Postgis JDBC Driver JTS Parser</name> | |
15 | <description>Parser between JTS and PostGIS geometry formats.</description> | |
16 | ||
17 | <properties /> | |
18 | ||
19 | <dependencies> | |
20 | <dependency> | |
21 | <groupId>net.postgis</groupId> | |
22 | <artifactId>postgis-jdbc</artifactId> | |
23 | <version>2021.1.0</version> | |
24 | </dependency> | |
25 | <dependency> | |
26 | <groupId>org.locationtech.jts</groupId> | |
27 | <artifactId>jts-core</artifactId> | |
28 | <version>${dependency.jts-version.version}</version> | |
29 | </dependency> | |
30 | <dependency> | |
31 | <groupId>org.locationtech.spatial4j</groupId> | |
32 | <artifactId>spatial4j</artifactId> | |
33 | <version>${dependency.spatial4j.version}</version> | |
34 | </dependency> | |
35 | <dependency> | |
36 | <groupId>net.postgis.tools</groupId> | |
37 | <artifactId>test-utils</artifactId> | |
38 | <version>2021.1.0</version> | |
39 | <scope>test</scope> | |
40 | </dependency> | |
41 | </dependencies> | |
42 | ||
43 | <build> | |
44 | <testResources> | |
45 | <testResource> | |
46 | <directory>src/test/resources</directory> | |
47 | </testResource> | |
48 | <testResource> | |
49 | <directory>src/test/resources-filtered</directory> | |
50 | <filtering>true</filtering> | |
51 | </testResource> | |
52 | </testResources> | |
53 | <plugins> | |
54 | <plugin> | |
55 | <artifactId>maven-jar-plugin</artifactId> | |
56 | <configuration> | |
57 | <archive> | |
58 | <manifestEntries> | |
59 | <Automatic-Module-Name>net.postgis.jdbc.jts</Automatic-Module-Name> | |
60 | </manifestEntries> | |
61 | </archive> | |
62 | </configuration> | |
63 | </plugin> | |
64 | <plugin> | |
65 | <groupId>org.apache.maven.plugins</groupId> | |
66 | <artifactId>maven-failsafe-plugin</artifactId> | |
67 | <executions> | |
68 | <execution> | |
69 | <id>integration-tests</id> | |
70 | <goals> | |
71 | <goal>integration-test</goal> | |
72 | <goal>verify</goal> | |
73 | </goals> | |
74 | <configuration> | |
75 | <skip>${maven.integration.test.skip}</skip> | |
76 | <forkCount>${failsafe.forkCount}</forkCount> | |
77 | <useSystemClassLoader>${failsafe.useSystemClassLoader}</useSystemClassLoader> | |
78 | <suiteXmlFiles> | |
79 | <suiteXmlFile>${project.build.testOutputDirectory}/testng-it.xml</suiteXmlFile> | |
80 | </suiteXmlFiles> | |
81 | </configuration> | |
82 | </execution> | |
83 | </executions> | |
84 | </plugin> | |
85 | <plugin> | |
86 | <groupId>org.apache.maven.plugins</groupId> | |
87 | <artifactId>maven-surefire-plugin</artifactId> | |
88 | <configuration> | |
89 | <skip>true</skip> | |
90 | </configuration> | |
91 | </plugin> | |
92 | </plugins> | |
93 | </build> | |
94 | ||
95 | </project> |
0 | module net.postgis.jdbc.jts { | |
1 | requires java.desktop; | |
2 | requires java.sql; | |
3 | ||
4 | requires org.locationtech.jts; | |
5 | requires org.postgresql.jdbc; | |
6 | ||
7 | requires spatial4j; | |
8 | ||
9 | requires net.postgis.geometry; | |
10 | requires net.postgis.jdbc; | |
11 | ||
12 | exports net.postgis.jdbc.jts; | |
13 | }⏎ |
0 | /* | |
1 | * JTSShape.java | |
2 | * | |
3 | * Binary Parser for JTS - relies on net.postgis V1.0.0+ package. | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package net.postgis.jdbc.jts; | |
26 | ||
27 | import org.locationtech.jts.geom.*; | |
28 | import org.locationtech.jts.geom.Point; | |
29 | import org.locationtech.jts.geom.Polygon; | |
30 | import org.locationtech.jts.geom.impl.PackedCoordinateSequence; | |
31 | ||
32 | import java.awt.*; | |
33 | import java.awt.geom.AffineTransform; | |
34 | import java.awt.geom.PathIterator; | |
35 | import java.awt.geom.Point2D; | |
36 | import java.awt.geom.Rectangle2D; | |
37 | ||
38 | public class JTSShape implements Shape { | |
39 | static GeometryFactory fac = new GeometryFactory(); | |
40 | ||
41 | Geometry geom; | |
42 | ||
43 | final static LinearRing[] NOSHELLS = {}; | |
44 | ||
45 | public JTSShape(Geometry _geom) { | |
46 | this.geom = _geom; | |
47 | } | |
48 | ||
49 | public JTSShape(JtsGeometry _geom) { | |
50 | this(_geom.getGeometry()); | |
51 | } | |
52 | ||
53 | public boolean contains(Point2D p) { | |
54 | return contains(p.getX(), p.getY()); | |
55 | } | |
56 | ||
57 | public boolean contains(double x, double y) { | |
58 | Coordinate c = new Coordinate(x, y); | |
59 | Point p = fac.createPoint(c); | |
60 | return geom.contains(p); | |
61 | } | |
62 | ||
63 | public boolean contains(Rectangle2D r) { | |
64 | return contains(r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight()); | |
65 | } | |
66 | ||
67 | public boolean contains(double x, double y, double w, double h) { | |
68 | Polygon p = createRect(x, y, w, h); | |
69 | return geom.contains(p); | |
70 | } | |
71 | ||
72 | protected Polygon createRect(double x, double y, double w, double h) { | |
73 | Coordinate[] coords = { new Coordinate(x, y), new Coordinate(x + w, y), new Coordinate(x + w, y + h) ,new Coordinate(x, y + h) ,new Coordinate(x, y) }; | |
74 | PackedCoordinateSequence shell = new PackedCoordinateSequence.Double(coords, 2); | |
75 | Polygon p = fac.createPolygon(fac.createLinearRing(shell), NOSHELLS); | |
76 | return p; | |
77 | } | |
78 | ||
79 | public Rectangle2D getBounds2D() { | |
80 | Envelope env = geom.getEnvelopeInternal(); | |
81 | return new Rectangle2D.Double(env.getMinX(), env.getMaxX(), env.getWidth(), env.getHeight()); | |
82 | } | |
83 | ||
84 | public Rectangle getBounds() { | |
85 | // We deal simple code for efficiency here, the getBounds() rounding | |
86 | // rules are ugly... | |
87 | return getBounds2D().getBounds(); | |
88 | } | |
89 | ||
90 | public PathIterator getPathIterator(AffineTransform at) { | |
91 | return getPathIterator(geom, at); | |
92 | } | |
93 | ||
94 | public PathIterator getPathIterator(AffineTransform at, double flatness) { | |
95 | // we don't have much work here, as we only have linear segments, no | |
96 | // "flattening" necessary. | |
97 | return getPathIterator(at); | |
98 | } | |
99 | ||
100 | public boolean intersects(Rectangle2D r) { | |
101 | return intersects(r.getMinX(), r.getMinY(), r.getWidth(), r.getHeight()); | |
102 | } | |
103 | ||
104 | public boolean intersects(double x, double y, double w, double h) { | |
105 | Polygon p = createRect(x, y, w, h); | |
106 | return geom.intersects(p); | |
107 | } | |
108 | ||
109 | public static GeometryPathIterator getPathIterator(Geometry geometry, AffineTransform _at) { | |
110 | if (geometry instanceof Point) { | |
111 | return new PointPathIterator((Point) geometry, _at); | |
112 | } else if (geometry instanceof LineString) { | |
113 | return new LineStringPathIterator((LineString) geometry, _at); | |
114 | } else if (geometry instanceof Polygon) { | |
115 | return new PolygonPathIterator((Polygon) geometry, _at); | |
116 | } else { | |
117 | return new GeometryCollectionPathIterator((GeometryCollection) geometry, _at); | |
118 | } | |
119 | } | |
120 | ||
121 | public static abstract class GeometryPathIterator implements PathIterator { | |
122 | ||
123 | protected final AffineTransform at; | |
124 | protected int index=0; | |
125 | ||
126 | GeometryPathIterator(AffineTransform _at) { | |
127 | this.at = _at; | |
128 | } | |
129 | ||
130 | public final int getWindingRule() { | |
131 | return PathIterator.WIND_EVEN_ODD; | |
132 | } | |
133 | ||
134 | public void next() { | |
135 | index++; | |
136 | } | |
137 | } | |
138 | ||
139 | public static class PointPathIterator extends GeometryPathIterator { | |
140 | final Point p; | |
141 | ||
142 | public PointPathIterator(Point _p, AffineTransform _at) { | |
143 | super(_at); | |
144 | p = _p; | |
145 | } | |
146 | ||
147 | public int currentSegment(float[] coords) { | |
148 | switch (index) { | |
149 | case 0: | |
150 | coords[0] = (float) p.getX(); | |
151 | coords[1] = (float) p.getY(); | |
152 | at.transform(coords, 0, coords, 0, 1); | |
153 | return PathIterator.SEG_MOVETO; | |
154 | case 1: | |
155 | return PathIterator.SEG_CLOSE; | |
156 | default: | |
157 | throw new IllegalStateException(); | |
158 | } | |
159 | } | |
160 | ||
161 | public int currentSegment(double[] coords) { | |
162 | switch (index) { | |
163 | case 0: | |
164 | coords[0] = p.getX(); | |
165 | coords[1] = p.getY(); | |
166 | at.transform(coords, 0, coords, 0, 1); | |
167 | return PathIterator.SEG_MOVETO; | |
168 | case 1: | |
169 | return PathIterator.SEG_CLOSE; | |
170 | default: | |
171 | throw new IllegalStateException(); | |
172 | } | |
173 | } | |
174 | ||
175 | public boolean isDone() { | |
176 | return index > 1; | |
177 | } | |
178 | } | |
179 | ||
180 | public static class LineStringPathIterator extends GeometryPathIterator { | |
181 | CoordinateSequence cs; | |
182 | ||
183 | final boolean isRing; | |
184 | ||
185 | public LineStringPathIterator(LineString ls, AffineTransform _at) { | |
186 | super(_at); | |
187 | cs = ls.getCoordinateSequence(); | |
188 | isRing = ls instanceof LinearRing; | |
189 | } | |
190 | ||
191 | /** | |
192 | * only to be called from PolygonPathIterator subclass | |
193 | * @param _cs A coordinate sequence to be used. | |
194 | */ | |
195 | protected void reInit(CoordinateSequence _cs) { | |
196 | cs = _cs; | |
197 | index=0; | |
198 | } | |
199 | ||
200 | public int currentSegment(float[] coords) { | |
201 | if (index == 0) { | |
202 | coords[0] = (float) cs.getOrdinate(index, 0); | |
203 | coords[1] = (float) cs.getOrdinate(index, 1); | |
204 | at.transform(coords, 0, coords, 0, 1); | |
205 | return PathIterator.SEG_MOVETO; | |
206 | } else if (index < cs.size()) { | |
207 | coords[0] = (float) cs.getOrdinate(index, 0); | |
208 | coords[1] = (float) cs.getOrdinate(index, 1); | |
209 | at.transform(coords, 0, coords, 0, 1); | |
210 | return PathIterator.SEG_LINETO; | |
211 | } else if (isRing && index == cs.size()) { | |
212 | return PathIterator.SEG_CLOSE; | |
213 | } else { | |
214 | throw new IllegalStateException(); | |
215 | } | |
216 | } | |
217 | ||
218 | public int currentSegment(double[] coords) { | |
219 | if (index == 0) { | |
220 | coords[0] = cs.getOrdinate(index, 0); | |
221 | coords[1] = cs.getOrdinate(index, 1); | |
222 | at.transform(coords, 0, coords, 0, 1); | |
223 | return PathIterator.SEG_MOVETO; | |
224 | } else if (index < cs.size()) { | |
225 | coords[0] = cs.getOrdinate(index, 0); | |
226 | coords[1] = cs.getOrdinate(index, 1); | |
227 | at.transform(coords, 0, coords, 0, 1); | |
228 | return PathIterator.SEG_LINETO; | |
229 | } else if (isRing && index == cs.size()) { | |
230 | return PathIterator.SEG_CLOSE; | |
231 | } else { | |
232 | throw new IllegalStateException(); | |
233 | } | |
234 | } | |
235 | ||
236 | public boolean isDone() { | |
237 | return isRing ? index > cs.size() : index >= cs.size(); | |
238 | } | |
239 | } | |
240 | ||
241 | public static class PolygonPathIterator extends LineStringPathIterator { | |
242 | final Polygon pg; | |
243 | int outerindex=-1; | |
244 | ||
245 | public PolygonPathIterator(Polygon _pg, AffineTransform _at) { | |
246 | super(_pg.getExteriorRing() ,_at); | |
247 | pg=_pg; | |
248 | index = -1; | |
249 | } | |
250 | ||
251 | public boolean isDone() { | |
252 | return outerindex >= pg.getNumInteriorRing(); | |
253 | } | |
254 | ||
255 | public void next() { | |
256 | super.next(); | |
257 | if (super.isDone()) { | |
258 | outerindex++; | |
259 | if (outerindex < pg.getNumInteriorRing()) { | |
260 | super.reInit(pg.getInteriorRingN(outerindex).getCoordinateSequence()); | |
261 | } | |
262 | } | |
263 | } | |
264 | } | |
265 | ||
266 | public static class GeometryCollectionPathIterator extends GeometryPathIterator { | |
267 | final GeometryCollection coll; | |
268 | GeometryPathIterator current; | |
269 | ||
270 | public GeometryCollectionPathIterator(GeometryCollection _coll, AffineTransform _at) { | |
271 | super(_at); | |
272 | coll = _coll; | |
273 | current = getPathIterator(coll.getGeometryN(index), _at); | |
274 | } | |
275 | ||
276 | public boolean isDone() { | |
277 | return index > coll.getNumGeometries(); | |
278 | } | |
279 | ||
280 | public void next() { | |
281 | current.next(); | |
282 | if (current.isDone()) { | |
283 | index++; | |
284 | if (index < coll.getNumGeometries()) { | |
285 | current = getPathIterator(coll.getGeometryN(index), at); | |
286 | } | |
287 | } | |
288 | } | |
289 | ||
290 | public int currentSegment(float[] coords) { | |
291 | return current.currentSegment(coords); | |
292 | } | |
293 | ||
294 | public int currentSegment(double[] coords) { | |
295 | return current.currentSegment(coords); | |
296 | } | |
297 | } | |
298 | } |
0 | /* | |
1 | * JtsBinaryParser.java | |
2 | * | |
3 | * Binary Parser for JTS - relies on net.postgis V1.0.0+ package. | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | package net.postgis.jdbc.jts; | |
25 | ||
26 | import org.locationtech.jts.geom.*; | |
27 | import org.locationtech.jts.geom.impl.PackedCoordinateSequence; | |
28 | import org.locationtech.spatial4j.context.jts.JtsSpatialContextFactory; | |
29 | import net.postgis.jdbc.geometry.binary.ByteGetter; | |
30 | import net.postgis.jdbc.geometry.binary.ByteGetter.BinaryByteGetter; | |
31 | import net.postgis.jdbc.geometry.binary.ByteGetter.StringByteGetter; | |
32 | import net.postgis.jdbc.geometry.binary.ValueGetter; | |
33 | ||
34 | /** | |
35 | * Parse binary representation of geometries. Currently, only text rep (hexed) | |
36 | * implementation is tested. | |
37 | * | |
38 | * It should be easy to add char[] and CharSequence ByteGetter instances, | |
39 | * although the latter one is not compatible with older jdks. | |
40 | * | |
41 | * I did not implement real unsigned 32-bit integers or emulate them with long, | |
42 | * as both java Arrays and Strings currently can have only 2^31-1 elements | |
43 | * (bytes), so we cannot even get or build Geometries with more than approx. | |
44 | * 2^28 coordinates (8 bytes each). | |
45 | * | |
46 | * @author Markus Schaber, markus.schaber@logix-tt.com | |
47 | * | |
48 | */ | |
49 | public class JtsBinaryParser { | |
50 | ||
51 | private JtsSpatialContextFactory jtsFactory = new JtsSpatialContextFactory(); | |
52 | ||
53 | /** | |
54 | * Get the appropriate ValueGetter for my endianness | |
55 | * | |
56 | * @param bytes | |
57 | * The appropriate Byte Getter | |
58 | * | |
59 | * @return the ValueGetter | |
60 | */ | |
61 | public static ValueGetter valueGetterForEndian(ByteGetter bytes) { | |
62 | if (bytes.get(0) == ValueGetter.XDR.NUMBER) { // XDR | |
63 | return new ValueGetter.XDR(bytes); | |
64 | } else if (bytes.get(0) == ValueGetter.NDR.NUMBER) { | |
65 | return new ValueGetter.NDR(bytes); | |
66 | } else { | |
67 | throw new IllegalArgumentException("Unknown Endian type:" + bytes.get(0)); | |
68 | } | |
69 | } | |
70 | ||
71 | ||
72 | /** | |
73 | * Parse a hex encoded geometry | |
74 | * @param value String containing the hex data to be parsed | |
75 | * @return the resulting parsed geometry | |
76 | */ | |
77 | public Geometry parse(String value) { | |
78 | StringByteGetter bytes = new ByteGetter.StringByteGetter(value); | |
79 | return parseGeometry(valueGetterForEndian(bytes)); | |
80 | } | |
81 | ||
82 | ||
83 | /** | |
84 | * Parse a binary encoded geometry. | |
85 | * @param value byte array containing the binary encoded geometru | |
86 | * @return the resulting parsed geometry | |
87 | */ | |
88 | public Geometry parse(byte[] value) { | |
89 | BinaryByteGetter bytes = new ByteGetter.BinaryByteGetter(value); | |
90 | return parseGeometry(valueGetterForEndian(bytes)); | |
91 | } | |
92 | ||
93 | ||
94 | /** | |
95 | * Parse a geometry starting at offset. | |
96 | * @param data ValueGetter for the data to be parsed | |
97 | * @return The resulting Geometry | |
98 | */ | |
99 | protected Geometry parseGeometry(ValueGetter data) { | |
100 | return parseGeometry(data, 0, false); | |
101 | } | |
102 | ||
103 | ||
104 | /** | |
105 | * Parse with a known geometry factory | |
106 | * @param data ValueGetter for the data to be parsed | |
107 | * @param srid the SRID to be used for parsing | |
108 | * @param inheritSrid flag to toggle inheriting SRIDs | |
109 | * @return The resulting Geometry | |
110 | */ | |
111 | protected Geometry parseGeometry(ValueGetter data, int srid, boolean inheritSrid) { | |
112 | byte endian = data.getByte(); // skip and test endian flag | |
113 | if (endian != data.endian) { | |
114 | throw new IllegalArgumentException("Endian inconsistency!"); | |
115 | } | |
116 | int typeword = data.getInt(); | |
117 | ||
118 | int realtype = typeword & 0x1FFFFFFF; // cut off high flag bits | |
119 | ||
120 | boolean haveZ = (typeword & 0x80000000) != 0; | |
121 | boolean haveM = (typeword & 0x40000000) != 0; | |
122 | boolean haveS = (typeword & 0x20000000) != 0; | |
123 | ||
124 | if (haveS) { | |
125 | int newsrid = net.postgis.jdbc.geometry.Geometry.parseSRID(data.getInt()); | |
126 | if (inheritSrid && newsrid != srid) { | |
127 | throw new IllegalArgumentException("Inconsistent srids in complex geometry: " + srid + ", " + newsrid); | |
128 | } else { | |
129 | srid = newsrid; | |
130 | } | |
131 | } else if (!inheritSrid) { | |
132 | srid = net.postgis.jdbc.geometry.Geometry.UNKNOWN_SRID; | |
133 | } | |
134 | ||
135 | Geometry result; | |
136 | switch (realtype) { | |
137 | case net.postgis.jdbc.geometry.Geometry.POINT: | |
138 | result = parsePoint(data, haveZ, haveM); | |
139 | break; | |
140 | case net.postgis.jdbc.geometry.Geometry.LINESTRING: | |
141 | result = parseLineString(data, haveZ, haveM); | |
142 | break; | |
143 | case net.postgis.jdbc.geometry.Geometry.POLYGON: | |
144 | result = parsePolygon(data, haveZ, haveM, srid); | |
145 | break; | |
146 | case net.postgis.jdbc.geometry.Geometry.MULTIPOINT: | |
147 | result = parseMultiPoint(data, srid); | |
148 | break; | |
149 | case net.postgis.jdbc.geometry.Geometry.MULTILINESTRING: | |
150 | result = parseMultiLineString(data, srid); | |
151 | break; | |
152 | case net.postgis.jdbc.geometry.Geometry.MULTIPOLYGON: | |
153 | result = parseMultiPolygon(data, srid); | |
154 | break; | |
155 | case net.postgis.jdbc.geometry.Geometry.GEOMETRYCOLLECTION: | |
156 | result = parseCollection(data, srid); | |
157 | break; | |
158 | default: | |
159 | throw new IllegalArgumentException("Unknown Geometry Type!"); | |
160 | } | |
161 | ||
162 | result.setSRID(srid); | |
163 | ||
164 | return result; | |
165 | } | |
166 | ||
167 | private Point parsePoint(ValueGetter data, boolean haveZ, boolean haveM) { | |
168 | double X = data.getDouble(); | |
169 | double Y = data.getDouble(); | |
170 | Point result; | |
171 | if (haveZ) { | |
172 | double Z = data.getDouble(); | |
173 | result = jtsFactory.getGeometryFactory().createPoint(new Coordinate(X, Y, Z)); | |
174 | } else { | |
175 | result = jtsFactory.getGeometryFactory().createPoint(new Coordinate(X, Y)); | |
176 | } | |
177 | ||
178 | if (haveM) { // skip M value | |
179 | data.getDouble(); | |
180 | } | |
181 | ||
182 | return result; | |
183 | } | |
184 | ||
185 | /** Parse an Array of "full" Geometries */ | |
186 | private void parseGeometryArray(ValueGetter data, Geometry[] container, int srid) { | |
187 | for (int i = 0; i < container.length; i++) { | |
188 | container[i] = parseGeometry(data, srid, true); | |
189 | } | |
190 | } | |
191 | ||
192 | /** | |
193 | * Parse an Array of "slim" Points (without endianness and type, part of | |
194 | * LinearRing and Linestring, but not MultiPoint! | |
195 | * | |
196 | * @param haveZ | |
197 | * @param haveM | |
198 | */ | |
199 | private CoordinateSequence parseCS(ValueGetter data, boolean haveZ, boolean haveM) { | |
200 | int count = data.getInt(); | |
201 | int dims = haveZ ? 3 : 2; | |
202 | CoordinateSequence cs = new PackedCoordinateSequence.Double(count, dims, 0); | |
203 | ||
204 | for (int i = 0; i < count; i++) { | |
205 | for (int d = 0; d < dims; d++) { | |
206 | cs.setOrdinate(i, d, data.getDouble()); | |
207 | } | |
208 | if (haveM) { // skip M value | |
209 | data.getDouble(); | |
210 | } | |
211 | } | |
212 | return cs; | |
213 | } | |
214 | ||
215 | private MultiPoint parseMultiPoint(ValueGetter data, int srid) { | |
216 | Point[] points = new Point[data.getInt()]; | |
217 | parseGeometryArray(data, points, srid); | |
218 | return jtsFactory.getGeometryFactory().createMultiPoint(points); | |
219 | } | |
220 | ||
221 | private LineString parseLineString(ValueGetter data, boolean haveZ, boolean haveM) { | |
222 | return jtsFactory.getGeometryFactory().createLineString(parseCS(data, haveZ, haveM)); | |
223 | } | |
224 | ||
225 | private LinearRing parseLinearRing(ValueGetter data, boolean haveZ, boolean haveM) { | |
226 | return jtsFactory.getGeometryFactory().createLinearRing(parseCS(data, haveZ, haveM)); | |
227 | } | |
228 | ||
229 | private Polygon parsePolygon(ValueGetter data, boolean haveZ, boolean haveM, int srid) { | |
230 | int holecount = data.getInt() - 1; | |
231 | LinearRing[] rings = new LinearRing[holecount]; | |
232 | LinearRing shell = parseLinearRing(data, haveZ, haveM); | |
233 | shell.setSRID(srid); | |
234 | for (int i = 0; i < holecount; i++) { | |
235 | rings[i] = parseLinearRing(data, haveZ, haveM); | |
236 | rings[i].setSRID(srid); | |
237 | } | |
238 | return jtsFactory.getGeometryFactory().createPolygon(shell, rings); | |
239 | } | |
240 | ||
241 | private MultiLineString parseMultiLineString(ValueGetter data, int srid) { | |
242 | int count = data.getInt(); | |
243 | LineString[] strings = new LineString[count]; | |
244 | parseGeometryArray(data, strings, srid); | |
245 | return jtsFactory.getGeometryFactory().createMultiLineString(strings); | |
246 | } | |
247 | ||
248 | private MultiPolygon parseMultiPolygon(ValueGetter data, int srid) { | |
249 | int count = data.getInt(); | |
250 | Polygon[] polys = new Polygon[count]; | |
251 | parseGeometryArray(data, polys, srid); | |
252 | return jtsFactory.getGeometryFactory().createMultiPolygon(polys); | |
253 | } | |
254 | ||
255 | private GeometryCollection parseCollection(ValueGetter data, int srid) { | |
256 | int count = data.getInt(); | |
257 | Geometry[] geoms = new Geometry[count]; | |
258 | parseGeometryArray(data, geoms, srid); | |
259 | return jtsFactory.getGeometryFactory().createGeometryCollection(geoms); | |
260 | } | |
261 | } |
0 | /* | |
1 | * JtsBinaryWriter.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - Binary Writer | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | package net.postgis.jdbc.jts; | |
25 | ||
26 | import org.locationtech.jts.geom.CoordinateSequence; | |
27 | import org.locationtech.jts.geom.Geometry; | |
28 | import org.locationtech.jts.geom.GeometryCollection; | |
29 | import org.locationtech.jts.geom.LineString; | |
30 | import org.locationtech.jts.geom.MultiLineString; | |
31 | import org.locationtech.jts.geom.MultiPoint; | |
32 | import org.locationtech.jts.geom.MultiPolygon; | |
33 | import org.locationtech.jts.geom.Point; | |
34 | import org.locationtech.jts.geom.Polygon; | |
35 | ||
36 | import net.postgis.jdbc.geometry.binary.ByteSetter; | |
37 | import net.postgis.jdbc.geometry.binary.ValueSetter; | |
38 | ||
39 | /** | |
40 | * Create binary representation of geometries. Currently, only text rep (hexed) | |
41 | * implementation is tested. Supports only 2 dimensional geometries. | |
42 | * | |
43 | * It should be easy to add char[] and CharSequence ByteGetter instances, | |
44 | * although the latter one is not compatible with older jdks. | |
45 | * | |
46 | * I did not implement real unsigned 32-bit integers or emulate them with long, | |
47 | * as both java Arrays and Strings currently can have only 2^31-1 elements | |
48 | * (bytes), so we cannot even get or build Geometries with more than approx. | |
49 | * 2^28 coordinates (8 bytes each). | |
50 | * | |
51 | * @author markus.schaber@logi-track.com | |
52 | * | |
53 | */ | |
54 | public class JtsBinaryWriter { | |
55 | ||
56 | /** | |
57 | * Get the appropriate ValueGetter for my endianness | |
58 | * | |
59 | * @param bytes The ByteSetter | |
60 | * @param endian The endian to be used | |
61 | * @return the appropriate ValueSetter for the specified endian | |
62 | */ | |
63 | public static ValueSetter valueSetterForEndian(ByteSetter bytes, byte endian) { | |
64 | if (endian == ValueSetter.XDR.NUMBER) { // XDR | |
65 | return new ValueSetter.XDR(bytes); | |
66 | } else if (endian == ValueSetter.NDR.NUMBER) { | |
67 | return new ValueSetter.NDR(bytes); | |
68 | } else { | |
69 | throw new IllegalArgumentException("Unknown Endian type:" + endian); | |
70 | } | |
71 | } | |
72 | ||
73 | /** | |
74 | * Write a hex encoded geometry | |
75 | * | |
76 | * Currently, geometries with more than 2 dimensions and measures are not | |
77 | * cleanly supported, but SRID is honored. | |
78 | * | |
79 | * @param geom The geometry to be written | |
80 | * @param REP The endianness representation to use for writing | |
81 | * @return String containing the hex-encoded geometry | |
82 | */ | |
83 | public String writeHexed(Geometry geom, byte REP) { | |
84 | int length = estimateBytes(geom); | |
85 | ByteSetter.StringByteSetter bytes = new ByteSetter.StringByteSetter(length); | |
86 | writeGeometry(geom, valueSetterForEndian(bytes, REP)); | |
87 | return bytes.result(); | |
88 | } | |
89 | ||
90 | public String writeHexed(Geometry geom) { | |
91 | return writeHexed(geom, ValueSetter.NDR.NUMBER); | |
92 | } | |
93 | ||
94 | /** | |
95 | * Write a binary encoded geometry. | |
96 | * | |
97 | * Currently, geometries with more than 2 dimensions and measures are not | |
98 | * cleanly supported, but SRID is honored. | |
99 | * | |
100 | * @param geom The geometry to be written | |
101 | * @param REP The endianness representation to use for writing | |
102 | * @return byte array containing the encoded geometry | |
103 | */ | |
104 | public byte[] writeBinary(Geometry geom, byte REP) { | |
105 | int length = estimateBytes(geom); | |
106 | ByteSetter.BinaryByteSetter bytes = new ByteSetter.BinaryByteSetter(length); | |
107 | writeGeometry(geom, valueSetterForEndian(bytes, REP)); | |
108 | return bytes.result(); | |
109 | } | |
110 | ||
111 | public byte[] writeBinary(Geometry geom) { | |
112 | return writeBinary(geom, ValueSetter.NDR.NUMBER); | |
113 | } | |
114 | ||
115 | ||
116 | /** | |
117 | * Parse a geometry starting at offset. | |
118 | * @param geom The Geometry to be written | |
119 | * @param dest The ValueSettr to write to | |
120 | */ | |
121 | protected void writeGeometry(Geometry geom, ValueSetter dest) { | |
122 | final int dimension; | |
123 | if (geom == null) { | |
124 | throw new NullPointerException(); | |
125 | } else if (geom.isEmpty()) { | |
126 | // don't set any flag bits | |
127 | dimension = 0; | |
128 | } else { | |
129 | dimension = getCoordDim(geom); | |
130 | if (dimension < 2 || dimension > 4) { | |
131 | throw new IllegalArgumentException("Unsupported geometry dimensionality: " + dimension); | |
132 | } | |
133 | } | |
134 | // write endian flag | |
135 | dest.setByte(dest.endian); | |
136 | ||
137 | // write typeword | |
138 | final int plaintype = getWKBType(geom); | |
139 | int typeword = plaintype; | |
140 | if (dimension == 3 || dimension == 4) { | |
141 | typeword |= 0x80000000; | |
142 | } | |
143 | if (dimension == 4) { | |
144 | typeword |= 0x40000000; | |
145 | } | |
146 | ||
147 | final boolean haveSrid = checkSrid(geom); | |
148 | if (haveSrid) { | |
149 | typeword |= 0x20000000; | |
150 | } | |
151 | ||
152 | dest.setInt(typeword); | |
153 | ||
154 | if (haveSrid) { | |
155 | dest.setInt(geom.getSRID()); | |
156 | } | |
157 | ||
158 | switch (plaintype) { | |
159 | case net.postgis.jdbc.geometry.Geometry.POINT: | |
160 | writePoint((Point) geom, dest); | |
161 | break; | |
162 | case net.postgis.jdbc.geometry.Geometry.LINESTRING: | |
163 | writeLineString((LineString) geom, dest); | |
164 | break; | |
165 | case net.postgis.jdbc.geometry.Geometry.POLYGON: | |
166 | writePolygon((Polygon) geom, dest); | |
167 | break; | |
168 | case net.postgis.jdbc.geometry.Geometry.MULTIPOINT: | |
169 | writeMultiPoint((MultiPoint) geom, dest); | |
170 | break; | |
171 | case net.postgis.jdbc.geometry.Geometry.MULTILINESTRING: | |
172 | writeMultiLineString((MultiLineString) geom, dest); | |
173 | break; | |
174 | case net.postgis.jdbc.geometry.Geometry.MULTIPOLYGON: | |
175 | writeMultiPolygon((MultiPolygon) geom, dest); | |
176 | break; | |
177 | case net.postgis.jdbc.geometry.Geometry.GEOMETRYCOLLECTION: | |
178 | writeCollection((GeometryCollection) geom, dest); | |
179 | break; | |
180 | default: | |
181 | throw new IllegalArgumentException("Unknown Geometry Type: " + plaintype); | |
182 | } | |
183 | } | |
184 | ||
185 | public static int getWKBType(Geometry geom) { | |
186 | // We always write empty geometries as empty collections - for OpenGIS | |
187 | // conformance | |
188 | if (geom.isEmpty()) { | |
189 | return net.postgis.jdbc.geometry.Geometry.GEOMETRYCOLLECTION; | |
190 | } else if (geom instanceof Point) { | |
191 | return net.postgis.jdbc.geometry.Geometry.POINT; | |
192 | } else if (geom instanceof org.locationtech.jts.geom.LineString) { | |
193 | return net.postgis.jdbc.geometry.Geometry.LINESTRING; | |
194 | } else if (geom instanceof org.locationtech.jts.geom.Polygon) { | |
195 | return net.postgis.jdbc.geometry.Geometry.POLYGON; | |
196 | } else if (geom instanceof MultiPoint) { | |
197 | return net.postgis.jdbc.geometry.Geometry.MULTIPOINT; | |
198 | } else if (geom instanceof MultiLineString) { | |
199 | return net.postgis.jdbc.geometry.Geometry.MULTILINESTRING; | |
200 | } else if (geom instanceof org.locationtech.jts.geom.MultiPolygon) { | |
201 | return net.postgis.jdbc.geometry.Geometry.MULTIPOLYGON; | |
202 | } if (geom instanceof org.locationtech.jts.geom.GeometryCollection) { | |
203 | return net.postgis.jdbc.geometry.Geometry.GEOMETRYCOLLECTION; | |
204 | } else { | |
205 | throw new IllegalArgumentException("Unknown Geometry Type: " + geom.getClass().getName()); | |
206 | } | |
207 | } | |
208 | ||
209 | /** | |
210 | * Writes a "slim" Point (without endiannes, srid ant type, only the | |
211 | * ordinates and measure. Used by writeGeometry. | |
212 | */ | |
213 | private void writePoint(Point geom, ValueSetter dest) { | |
214 | writeCoordinates(geom.getCoordinateSequence(), getCoordDim(geom), dest); | |
215 | } | |
216 | ||
217 | /** | |
218 | * Write a CoordinateSequence, part of LinearRing and Linestring, but not | |
219 | * MultiPoint! | |
220 | */ | |
221 | private void writeCoordinates(CoordinateSequence seq, int dims, ValueSetter dest) { | |
222 | for (int i = 0; i < seq.size(); i++) { | |
223 | for (int d = 0; d < dims; d++) { | |
224 | dest.setDouble(seq.getOrdinate(i, d)); | |
225 | } | |
226 | } | |
227 | } | |
228 | ||
229 | private void writeMultiPoint(MultiPoint geom, ValueSetter dest) { | |
230 | dest.setInt(geom.getNumPoints()); | |
231 | for (int i = 0; i < geom.getNumPoints(); i++) { | |
232 | writeGeometry(geom.getGeometryN(i), dest); | |
233 | } | |
234 | } | |
235 | ||
236 | private void writeLineString(LineString geom, ValueSetter dest) { | |
237 | dest.setInt(geom.getNumPoints()); | |
238 | writeCoordinates(geom.getCoordinateSequence(), getCoordDim(geom), dest); | |
239 | } | |
240 | ||
241 | private void writePolygon(Polygon geom, ValueSetter dest) { | |
242 | dest.setInt(geom.getNumInteriorRing() + 1); | |
243 | writeLineString(geom.getExteriorRing(), dest); | |
244 | for (int i = 0; i < geom.getNumInteriorRing(); i++) { | |
245 | writeLineString(geom.getInteriorRingN(i), dest); | |
246 | } | |
247 | } | |
248 | ||
249 | private void writeMultiLineString(MultiLineString geom, ValueSetter dest) { | |
250 | writeGeometryArray(geom, dest); | |
251 | } | |
252 | ||
253 | private void writeMultiPolygon(MultiPolygon geom, ValueSetter dest) { | |
254 | writeGeometryArray(geom, dest); | |
255 | } | |
256 | ||
257 | private void writeCollection(GeometryCollection geom, ValueSetter dest) { | |
258 | writeGeometryArray(geom, dest); | |
259 | } | |
260 | ||
261 | private void writeGeometryArray(Geometry geom, ValueSetter dest) { | |
262 | dest.setInt(geom.getNumGeometries()); | |
263 | for (int i = 0; i < geom.getNumGeometries(); i++) { | |
264 | writeGeometry(geom.getGeometryN(i), dest); | |
265 | } | |
266 | } | |
267 | ||
268 | ||
269 | /** | |
270 | * Estimate how much bytes a geometry will need in WKB. | |
271 | * @param geom Geometry to estimate | |
272 | * @return number of bytes needed | |
273 | */ | |
274 | protected int estimateBytes(Geometry geom) { | |
275 | int result = 0; | |
276 | ||
277 | // write endian flag | |
278 | result += 1; | |
279 | ||
280 | // write typeword | |
281 | result += 4; | |
282 | ||
283 | if (checkSrid(geom)) { | |
284 | result += 4; | |
285 | } | |
286 | ||
287 | switch (getWKBType(geom)) { | |
288 | case net.postgis.jdbc.geometry.Geometry.POINT: | |
289 | result += estimatePoint((Point) geom); | |
290 | break; | |
291 | case net.postgis.jdbc.geometry.Geometry.LINESTRING: | |
292 | result += estimateLineString((LineString) geom); | |
293 | break; | |
294 | case net.postgis.jdbc.geometry.Geometry.POLYGON: | |
295 | result += estimatePolygon((Polygon) geom); | |
296 | break; | |
297 | case net.postgis.jdbc.geometry.Geometry.MULTIPOINT: | |
298 | result += estimateMultiPoint((MultiPoint) geom); | |
299 | break; | |
300 | case net.postgis.jdbc.geometry.Geometry.MULTILINESTRING: | |
301 | result += estimateMultiLineString((MultiLineString) geom); | |
302 | break; | |
303 | case net.postgis.jdbc.geometry.Geometry.MULTIPOLYGON: | |
304 | result += estimateMultiPolygon((MultiPolygon) geom); | |
305 | break; | |
306 | case net.postgis.jdbc.geometry.Geometry.GEOMETRYCOLLECTION: | |
307 | result += estimateCollection((GeometryCollection) geom); | |
308 | break; | |
309 | default: | |
310 | throw new IllegalArgumentException("Unknown Geometry Type: " + getWKBType(geom)); | |
311 | } | |
312 | return result; | |
313 | } | |
314 | ||
315 | private boolean checkSrid(Geometry geom) { | |
316 | final int srid = geom.getSRID(); | |
317 | return (srid > 0); | |
318 | } | |
319 | ||
320 | private int estimatePoint(Point geom) { | |
321 | return 8 * getCoordDim(geom); | |
322 | } | |
323 | ||
324 | /** Write an Array of "full" Geometries */ | |
325 | private int estimateGeometryArray(Geometry container) { | |
326 | int result = 0; | |
327 | for (int i = 0; i < container.getNumGeometries(); i++) { | |
328 | result += estimateBytes(container.getGeometryN(i)); | |
329 | } | |
330 | return result; | |
331 | } | |
332 | ||
333 | /** Estimate an array of "fat" Points */ | |
334 | private int estimateMultiPoint(MultiPoint geom) { | |
335 | // int size | |
336 | int result = 4; | |
337 | if (geom.getNumGeometries() > 0) { | |
338 | // We can shortcut here, compared to estimateGeometryArray, as all | |
339 | // subgeoms have the same fixed size | |
340 | result += geom.getNumGeometries() * estimateBytes(geom.getGeometryN(0)); | |
341 | } | |
342 | return result; | |
343 | } | |
344 | ||
345 | private int estimateLineString(LineString geom) { | |
346 | if (geom == null || geom.getNumGeometries() == 0) { | |
347 | return 0; | |
348 | } else { | |
349 | return 4 + 8 * getCoordSequenceDim(geom.getCoordinateSequence()) * geom.getCoordinateSequence().size(); | |
350 | } | |
351 | } | |
352 | ||
353 | private int estimatePolygon(Polygon geom) { | |
354 | // int length | |
355 | int result = 4; | |
356 | result += estimateLineString(geom.getExteriorRing()); | |
357 | for (int i = 0; i < geom.getNumInteriorRing(); i++) { | |
358 | result += estimateLineString(geom.getInteriorRingN(i)); | |
359 | } | |
360 | return result; | |
361 | } | |
362 | ||
363 | private int estimateMultiLineString(MultiLineString geom) { | |
364 | // 4-byte count + subgeometries | |
365 | return 4 + estimateGeometryArray(geom); | |
366 | } | |
367 | ||
368 | private int estimateMultiPolygon(MultiPolygon geom) { | |
369 | // 4-byte count + subgeometries | |
370 | return 4 + estimateGeometryArray(geom); | |
371 | } | |
372 | ||
373 | private int estimateCollection(GeometryCollection geom) { | |
374 | // 4-byte count + subgeometries | |
375 | return 4 + estimateGeometryArray(geom); | |
376 | } | |
377 | ||
378 | public static final int getCoordDim(Geometry geom) { | |
379 | if (geom.isEmpty()) { | |
380 | return 0; | |
381 | } | |
382 | if (geom instanceof Point) { | |
383 | return getCoordSequenceDim(((Point) geom).getCoordinateSequence()); | |
384 | } else if (geom instanceof LineString) { | |
385 | return getCoordSequenceDim(((LineString) geom).getCoordinateSequence()); | |
386 | } else if (geom instanceof Polygon) { | |
387 | return getCoordSequenceDim(((Polygon) geom).getExteriorRing().getCoordinateSequence()); | |
388 | } else { | |
389 | return getCoordDim(geom.getGeometryN(0)); | |
390 | } | |
391 | } | |
392 | ||
393 | public static final int getCoordSequenceDim(CoordinateSequence coords) { | |
394 | if (coords == null || coords.size() == 0) | |
395 | return 0; | |
396 | // JTS has a really strange way to handle dimensions! | |
397 | // Just have a look at PackedCoordinateSequence and | |
398 | // CoordinateArraySequence | |
399 | int dimensions = coords.getDimension(); | |
400 | if (dimensions == 3) { | |
401 | // CoordinateArraySequence will always return 3, so we have to | |
402 | // check, if | |
403 | // the third ordinate contains NaN, then the geom is actually | |
404 | // 2-dimensional | |
405 | return Double.isNaN(coords.getOrdinate(0, CoordinateSequence.Z)) ? 2 : 3; | |
406 | } else { | |
407 | return dimensions; | |
408 | } | |
409 | } | |
410 | } |
0 | /* | |
1 | * JtsGeometry.java | |
2 | * | |
3 | * Wrapper for PostgreSQL JDBC driver to allow transparent reading and writing | |
4 | * of JTS geometries | |
5 | * | |
6 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
7 | * | |
8 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public | |
21 | * License along with this library; if not, write to the Free Software | |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
23 | * | |
24 | */ | |
25 | ||
26 | package net.postgis.jdbc.jts; | |
27 | ||
28 | import java.sql.SQLException; | |
29 | ||
30 | import org.postgresql.util.PGobject; | |
31 | ||
32 | import org.locationtech.jts.geom.CoordinateSequenceFactory; | |
33 | import org.locationtech.jts.geom.Geometry; | |
34 | import org.locationtech.jts.geom.GeometryCollection; | |
35 | import org.locationtech.jts.geom.GeometryFactory; | |
36 | import org.locationtech.jts.geom.Polygon; | |
37 | import org.locationtech.jts.geom.PrecisionModel; | |
38 | import org.locationtech.jts.geom.impl.PackedCoordinateSequenceFactory; | |
39 | import org.locationtech.jts.io.WKTReader; | |
40 | ||
41 | /** | |
42 | * JTS Geometry SQL wrapper. Supports PostGIS 1.x (lwgeom hexwkb) for writing | |
43 | * and both PostGIS 0.x (EWKT) and 1.x (lwgeom hexwkb) for reading. | |
44 | * | |
45 | * @author Markus Schaber | |
46 | */ | |
47 | ||
48 | public class JtsGeometry extends PGobject { | |
49 | /* JDK 1.5 Serialization */ | |
50 | private static final long serialVersionUID = 0x100; | |
51 | ||
52 | Geometry geom; | |
53 | ||
54 | final static JtsBinaryParser bp = new JtsBinaryParser(); | |
55 | ||
56 | final static JtsBinaryWriter bw = new JtsBinaryWriter(); | |
57 | ||
58 | final static PrecisionModel prec = new PrecisionModel(); | |
59 | ||
60 | final static CoordinateSequenceFactory csfac = PackedCoordinateSequenceFactory.DOUBLE_FACTORY; | |
61 | ||
62 | final static GeometryFactory geofac = new GeometryFactory(prec, 0, csfac); | |
63 | ||
64 | static final WKTReader reader = new WKTReader(geofac); | |
65 | ||
66 | /** Constructor called by JDBC drivers */ | |
67 | public JtsGeometry() { | |
68 | setType("geometry"); | |
69 | } | |
70 | ||
71 | public JtsGeometry(Geometry geom) { | |
72 | this(); | |
73 | this.geom = geom; | |
74 | } | |
75 | ||
76 | public JtsGeometry(String value) throws SQLException { | |
77 | this(); | |
78 | setValue(value); | |
79 | } | |
80 | ||
81 | public void setValue(String value) throws SQLException { | |
82 | geom = geomFromString(value); | |
83 | } | |
84 | ||
85 | public static Geometry geomFromString(String value) throws SQLException { | |
86 | try { | |
87 | value = value.trim(); | |
88 | if (value.startsWith("00") || value.startsWith("01")) { | |
89 | return bp.parse(value); | |
90 | } else { | |
91 | Geometry result; | |
92 | // no srid := 0 in JTS world | |
93 | int srid = 0; | |
94 | // break up geometry into srid and wkt | |
95 | if (value.startsWith("SRID=")) { | |
96 | String[] temp = value.split(";"); | |
97 | value = temp[1].trim(); | |
98 | srid = Integer.parseInt(temp[0].substring(5)); | |
99 | } | |
100 | ||
101 | result = reader.read(value); | |
102 | setSridRecurse(result, srid); | |
103 | return result; | |
104 | } | |
105 | } catch (Exception E) { | |
106 | E.printStackTrace(); | |
107 | throw new SQLException("Error parsing SQL data:" + E); | |
108 | } | |
109 | } | |
110 | ||
111 | ||
112 | /** | |
113 | * Recursively set a srid for the geometry and all subgeometries | |
114 | * @param geom Geometry to work on | |
115 | * @param srid SRID to be set to | |
116 | */ | |
117 | public static void setSridRecurse(final Geometry geom, final int srid) { | |
118 | geom.setSRID(srid); | |
119 | if (geom instanceof GeometryCollection) { | |
120 | final int subcnt = geom.getNumGeometries(); | |
121 | for (int i = 0; i < subcnt; i++) { | |
122 | setSridRecurse(geom.getGeometryN(i), srid); | |
123 | } | |
124 | } else if (geom instanceof Polygon) { | |
125 | Polygon poly = (Polygon) geom; | |
126 | poly.getExteriorRing().setSRID(srid); | |
127 | final int subcnt = poly.getNumInteriorRing(); | |
128 | for (int i = 0; i < subcnt; i++) { | |
129 | poly.getInteriorRingN(i).setSRID(srid); | |
130 | } | |
131 | } | |
132 | } | |
133 | ||
134 | public Geometry getGeometry() { | |
135 | return geom; | |
136 | } | |
137 | ||
138 | public String toString() { | |
139 | return geom.toString(); | |
140 | } | |
141 | ||
142 | public String getValue() { | |
143 | return bw.writeHexed(getGeometry()); | |
144 | } | |
145 | ||
146 | public Object clone() { | |
147 | JtsGeometry obj = new JtsGeometry(geom); | |
148 | obj.setType(type); | |
149 | return obj; | |
150 | } | |
151 | ||
152 | public boolean equals(Object obj) { | |
153 | if ((obj != null) && (obj instanceof JtsGeometry)) { | |
154 | Geometry other = ((JtsGeometry) obj).geom; | |
155 | if (this.geom == other) { // handles identity as well as both | |
156 | // ==null | |
157 | return true; | |
158 | } else if (this.geom != null && other != null) { | |
159 | return other.equals(this.geom); | |
160 | } | |
161 | } | |
162 | return false; | |
163 | } | |
164 | } |
0 | /* | |
1 | * JtsGisWrapper.java | |
2 | * | |
3 | * Allows transparent usage of JTS Geometry classes via PostgreSQL JDBC driver | |
4 | * connected to a PostGIS enabled PostgreSQL server. | |
5 | * | |
6 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
7 | * | |
8 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public | |
21 | * License along with this library; if not, write to the Free Software | |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
23 | * | |
24 | */ | |
25 | ||
26 | package net.postgis.jdbc.jts; | |
27 | ||
28 | import org.postgresql.Driver; | |
29 | import org.postgresql.PGConnection; | |
30 | ||
31 | import java.sql.Connection; | |
32 | import java.sql.SQLException; | |
33 | import java.util.Properties; | |
34 | ||
35 | /** | |
36 | * JtsGisWrapper | |
37 | * | |
38 | * Wraps the PostGreSQL Driver to add the JTS/PostGIS Object Classes. | |
39 | * | |
40 | * This method currently works with J2EE DataSource implementations, and with | |
41 | * DriverManager framework. | |
42 | * | |
43 | * Simply replace the "jdbc:postgresql:" with a "jdbc:postgresql_JTS" in the | |
44 | * jdbc URL. | |
45 | * | |
46 | * @author markus.schaber@logix-tt.com | |
47 | * | |
48 | */ | |
49 | public class JtsGisWrapper extends Driver { | |
50 | ||
51 | private static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; | |
52 | private static final String POSTGIS_PROTOCOL = "jdbc:postgresql_JTS:"; | |
53 | public static final String REVISION = "$Revision$"; | |
54 | ||
55 | public JtsGisWrapper() { | |
56 | super(); | |
57 | } | |
58 | ||
59 | static { | |
60 | try { | |
61 | // Analogy to org.postgresql.Driver | |
62 | java.sql.DriverManager.registerDriver(new JtsGisWrapper()); | |
63 | } catch (SQLException e) { | |
64 | e.printStackTrace(); | |
65 | } | |
66 | } | |
67 | ||
68 | /** | |
69 | * Creates a postgresql connection, and then adds the PostGIS data types to | |
70 | * it calling addpgtypes() | |
71 | * | |
72 | * @param url the URL of the database to connect to | |
73 | * @param info a list of arbitrary tag/value pairs as connection arguments | |
74 | * @return a connection to the URL or null if it isnt us | |
75 | * @exception SQLException if a database access error occurs | |
76 | * | |
77 | * @see java.sql.Driver#connect | |
78 | * @see org.postgresql.Driver | |
79 | */ | |
80 | public java.sql.Connection connect(String url, Properties info) throws SQLException { | |
81 | url = mangleURL(url); | |
82 | Connection result = super.connect(url, info); | |
83 | addGISTypes((PGConnection) result); | |
84 | return result; | |
85 | } | |
86 | ||
87 | /** | |
88 | * Adds the JTS/PostGIS Data types to a PG Connection. | |
89 | * @param pgconn The PGConnection object to add the types to | |
90 | * @throws SQLException when an SQLException occurs | |
91 | */ | |
92 | public static void addGISTypes(PGConnection pgconn) throws SQLException { | |
93 | pgconn.addDataType("geometry", net.postgis.jdbc.jts.JtsGeometry.class); | |
94 | pgconn.addDataType("box3d", net.postgis.jdbc.PGbox3d.class); | |
95 | pgconn.addDataType("box2d", net.postgis.jdbc.PGbox2d.class); | |
96 | } | |
97 | ||
98 | /** | |
99 | * Mangles the PostGIS URL to return the original PostGreSQL URL | |
100 | * | |
101 | * @param url String containing the url to be "mangled" | |
102 | * @return "mangled" string | |
103 | * @throws SQLException when a SQLException occurs | |
104 | */ | |
105 | public static String mangleURL(String url) throws SQLException { | |
106 | if (url.startsWith(POSTGIS_PROTOCOL)) { | |
107 | return POSTGRES_PROTOCOL + url.substring(POSTGIS_PROTOCOL.length()); | |
108 | } else { | |
109 | throw new SQLException("Unknown protocol or subprotocol in url " + url); | |
110 | } | |
111 | } | |
112 | ||
113 | /** | |
114 | * Returns true if the driver thinks it can open a connection to the given | |
115 | * URL. Typically, drivers will return true if they understand the | |
116 | * subprotocol specified in the URL and false if they don't. Our protocols | |
117 | * start with jdbc:postgresql_postGIS: | |
118 | * | |
119 | * @see java.sql.Driver#acceptsURL | |
120 | * @param url the URL of the driver | |
121 | * @return true if this driver accepts the given URL | |
122 | */ | |
123 | public boolean acceptsURL(String url) { | |
124 | try { | |
125 | url = mangleURL(url); | |
126 | } catch (SQLException e) { | |
127 | return false; | |
128 | } | |
129 | return super.acceptsURL(url); | |
130 | } | |
131 | ||
132 | /** | |
133 | * Gets the underlying drivers major version number | |
134 | * | |
135 | * @return the drivers major version number | |
136 | */ | |
137 | ||
138 | public int getMajorVersion() { | |
139 | return super.getMajorVersion(); | |
140 | } | |
141 | ||
142 | /** | |
143 | * Get the underlying drivers minor version number | |
144 | * | |
145 | * @return the drivers minor version number | |
146 | */ | |
147 | public int getMinorVersion() { | |
148 | return super.getMinorVersion(); | |
149 | } | |
150 | ||
151 | /** | |
152 | * Returns our own CVS version plus postgres Version | |
153 | * | |
154 | * @return String representation of the version | |
155 | */ | |
156 | public static String getVersion() { | |
157 | return "JtsGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); | |
158 | } | |
159 | } |
0 | /* | |
1 | * JtsWrapper.java | |
2 | * | |
3 | * Allows transparent usage of JTS Geometry classes via PostgreSQL JDBC driver | |
4 | * connected to a PostGIS enabled PostgreSQL server. | |
5 | * | |
6 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
7 | * | |
8 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
9 | * | |
10 | * This library is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public | |
21 | * License along with this library; if not, write to the Free Software | |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
23 | * | |
24 | */ | |
25 | ||
26 | package net.postgis.jdbc.jts; | |
27 | ||
28 | import java.sql.Connection; | |
29 | import java.sql.SQLException; | |
30 | import java.util.Properties; | |
31 | import java.util.logging.Level; | |
32 | import java.util.logging.Logger; | |
33 | ||
34 | import org.postgresql.Driver; | |
35 | import org.postgresql.PGConnection; | |
36 | ||
37 | /** | |
38 | * JtsWrapper | |
39 | * | |
40 | * Wraps the PostGreSQL Driver to add the JTS/PostGIS Object Classes. | |
41 | * | |
42 | * This method currently works with J2EE DataSource implementations, and with | |
43 | * DriverManager framework. | |
44 | * | |
45 | * Simply replace the "jdbc:postgresql:" with a "jdbc:postgres_jts:" in the jdbc | |
46 | * URL. | |
47 | * | |
48 | * When using the drivermanager, you need to initialize JtsWrapper instead of | |
49 | * (or in addition to) org.postgresql.Driver. When using a J2EE DataSource | |
50 | * implementation, set the driver class property in the datasource config, the | |
51 | * following works for jboss: | |
52 | * | |
53 | * <driver-class>net.postgis.jdbc.jts.PostGisWrapper</driver-class> | |
54 | * | |
55 | * @author markus.schaber@logix-tt.com | |
56 | * | |
57 | */ | |
58 | public class JtsWrapper extends Driver { | |
59 | ||
60 | protected static final Logger logger = Logger.getLogger("net.postgis.jdbc.DriverWrapper"); | |
61 | ||
62 | private static final String POSTGRES_PROTOCOL = "jdbc:postgresql:"; | |
63 | private static final String POSTGIS_PROTOCOL = "jdbc:postgres_jts:"; | |
64 | public static final String REVISION = "$Revision$"; | |
65 | ||
66 | public JtsWrapper() { | |
67 | super(); | |
68 | } | |
69 | ||
70 | static { | |
71 | try { | |
72 | // Try to register ourself to the DriverManager | |
73 | java.sql.DriverManager.registerDriver(new JtsWrapper()); | |
74 | } catch (SQLException e) { | |
75 | logger.log(Level.WARNING, "Error registering PostgreSQL Jts Wrapper Driver", e); | |
76 | } | |
77 | } | |
78 | ||
79 | /** | |
80 | * Creates a postgresql connection, and then adds the JTS GIS data types to | |
81 | * it calling addpgtypes() | |
82 | * | |
83 | * @param url the URL of the database to connect to | |
84 | * @param info a list of arbitrary tag/value pairs as connection arguments | |
85 | * @return a connection to the URL or null if it isnt us | |
86 | * @exception SQLException if a database access error occurs | |
87 | * | |
88 | * @see java.sql.Driver#connect | |
89 | * @see org.postgresql.Driver | |
90 | */ | |
91 | public java.sql.Connection connect(String url, Properties info) throws SQLException { | |
92 | url = mangleURL(url); | |
93 | Connection result = super.connect(url, info); | |
94 | addGISTypes((PGConnection)result); | |
95 | return result; | |
96 | } | |
97 | ||
98 | /** | |
99 | * Adds the JTS/PostGIS Data types to a PG Connection. | |
100 | * @param pgconn The PGConnection object to add the types to | |
101 | * @throws SQLException when an SQLException occurs | |
102 | */ | |
103 | public static void addGISTypes(PGConnection pgconn) throws SQLException { | |
104 | pgconn.addDataType("geometry", net.postgis.jdbc.jts.JtsGeometry.class); | |
105 | } | |
106 | ||
107 | /** | |
108 | * Mangles the PostGIS URL to return the original PostGreSQL URL | |
109 | * | |
110 | * @param url String containing the url to be "mangled" | |
111 | * @return "mangled" string | |
112 | * @throws SQLException when a SQLException occurs | |
113 | */ | |
114 | public static String mangleURL(String url) throws SQLException { | |
115 | if (url.startsWith(POSTGIS_PROTOCOL)) { | |
116 | return POSTGRES_PROTOCOL + url.substring(POSTGIS_PROTOCOL.length()); | |
117 | } else { | |
118 | throw new SQLException("Unknown protocol or subprotocol in url " + url); | |
119 | } | |
120 | } | |
121 | ||
122 | /** | |
123 | * Check whether the driver thinks he can handle the given URL. | |
124 | * | |
125 | * @see java.sql.Driver#acceptsURL | |
126 | * @param url the URL of the driver | |
127 | * @return true if this driver accepts the given URL | |
128 | */ | |
129 | public boolean acceptsURL(String url) { | |
130 | try { | |
131 | url = mangleURL(url); | |
132 | } catch (SQLException e) { | |
133 | return false; | |
134 | } | |
135 | return super.acceptsURL(url); | |
136 | } | |
137 | ||
138 | /** | |
139 | * Gets the underlying drivers major version number | |
140 | * | |
141 | * @return the drivers major version number | |
142 | */ | |
143 | ||
144 | public int getMajorVersion() { | |
145 | return super.getMajorVersion(); | |
146 | } | |
147 | ||
148 | /** | |
149 | * Get the underlying drivers minor version number | |
150 | * | |
151 | * @return the drivers minor version number | |
152 | */ | |
153 | public int getMinorVersion() { | |
154 | return super.getMinorVersion(); | |
155 | } | |
156 | ||
157 | /** | |
158 | * Returns our own CVS version plus postgres Version | |
159 | * | |
160 | * @return String representation of the version | |
161 | */ | |
162 | public static String getVersion() { | |
163 | return "JtsGisWrapper " + REVISION + ", wrapping " + Driver.getVersion(); | |
164 | } | |
165 | } |
0 | <body><p>Parser between JTS and PostGIS geometry formats.</p></body>⏎ |
0 | /* | |
1 | * JtsParserTest.java | |
2 | * | |
3 | * JtsParserTest for JTS - relies on net.postgis V1.0.0+ package. | |
4 | * | |
5 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 | * | |
21 | */ | |
22 | ||
23 | package net.postgis.jdbc.jts; | |
24 | ||
25 | ||
26 | import net.postgis.jdbc.geometry.binary.ValueSetter; | |
27 | ||
28 | import org.locationtech.jts.geom.*; | |
29 | import net.postgis.tools.testutils.TestContainerController; | |
30 | import org.slf4j.Logger; | |
31 | import org.slf4j.LoggerFactory; | |
32 | import org.testng.Assert; | |
33 | import org.testng.ITestContext; | |
34 | import org.testng.annotations.AfterClass; | |
35 | import org.testng.annotations.BeforeClass; | |
36 | import org.testng.annotations.Test; | |
37 | ||
38 | import java.sql.*; | |
39 | ||
40 | ||
41 | /** | |
42 | * JtsParseTest | |
43 | * | |
44 | * This test class was adapted from the {@code JtsTestParsr} example standalone class. | |
45 | * It is meant to be run in standalone mode or run against a PostGIS database, but it will need to be | |
46 | * fixed to run against a PostGIS database as it currently fails in some places with an error: | |
47 | * {@literal function asewkb(geometry) does not exist} | |
48 | */ | |
49 | public class JtsParserTest { | |
50 | ||
51 | private static final Logger logger = LoggerFactory.getLogger(JtsParserTest.class); | |
52 | ||
53 | private static final String JTS_WRAPPER_CLASS_NAME = "net.postgis.jdbc.jts.JtsWrapper"; | |
54 | ||
55 | /** The srid we use for the srid tests */ | |
56 | public static final int SRID = 4326; | |
57 | ||
58 | /** The string prefix we get for the srid tests */ | |
59 | public static final String SRIDPREFIX = "SRID=" + SRID + ";"; | |
60 | ||
61 | /** | |
62 | * Our set of geometries to test. | |
63 | */ | |
64 | public static final String ALL = "ALL"; | |
65 | public static final String ONLY10 = "ONLY10"; | |
66 | public static final String EQUAL10 = "EQUAL10"; | |
67 | public static final String[][] testset = new String[][] { | |
68 | { ALL, // 2D | |
69 | "POINT(10 10)" }, | |
70 | { ALL, // 3D with 3rd coordinate set to 0 | |
71 | "POINT(10 10 0)" }, | |
72 | { ALL, // 3D | |
73 | "POINT(10 10 20)" }, | |
74 | { ALL, "MULTIPOINT(11 12, 20 20)" }, | |
75 | { ALL, "MULTIPOINT(11 12 13, 20 20 20)" }, | |
76 | { ALL, "LINESTRING(10 10,20 20,50 50,34 34)" }, | |
77 | { ALL, "LINESTRING(10 10 20,20 20 20,50 50 50,34 34 34)" }, | |
78 | { ALL, "POLYGON((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))" }, | |
79 | { ALL, "POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))" }, | |
80 | { | |
81 | ALL, | |
82 | "MULTIPOLYGON(((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)),((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5)))" }, | |
83 | { | |
84 | ALL, | |
85 | "MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))" }, | |
86 | { ALL, "MULTILINESTRING((10 10,20 10,20 20,20 10,10 10),(5 5,5 6,6 6,6 5,5 5))" }, | |
87 | { ALL, "MULTILINESTRING((10 10 5,20 10 5,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))" }, | |
88 | { ALL, "GEOMETRYCOLLECTION(POINT(10 10),POINT(20 20))" }, | |
89 | { ALL, "GEOMETRYCOLLECTION(POINT(10 10 20),POINT(20 20 20))" }, | |
90 | { | |
91 | ALL, | |
92 | "GEOMETRYCOLLECTION(LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34))" }, | |
93 | { | |
94 | ALL, | |
95 | "GEOMETRYCOLLECTION(POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))" }, | |
96 | { ONLY10, // Cannot be parsed by 0.X servers | |
97 | "GEOMETRYCOLLECTION(MULTIPOINT(10 10 10, 20 20 20),MULTIPOINT(10 10 10, 20 20 20))" }, | |
98 | { EQUAL10, // PostGIs 0.X "flattens" this geometry, so it is not | |
99 | // equal after reparsing. | |
100 | "GEOMETRYCOLLECTION(MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))" }, | |
101 | { EQUAL10,// PostGIs 0.X "flattens" this geometry, so it is not | |
102 | // equal | |
103 | // after reparsing. | |
104 | "GEOMETRYCOLLECTION(MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))))" }, | |
105 | { | |
106 | ALL, | |
107 | "GEOMETRYCOLLECTION(POINT(10 10 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))" }, | |
108 | { ONLY10, // Collections that contain both X and MultiX do not | |
109 | // work on | |
110 | // PostGIS 0.x | |
111 | "GEOMETRYCOLLECTION(POINT(10 10 20),MULTIPOINT(10 10 10, 20 20 20),LINESTRING(10 10 20,20 20 20, 50 50 50, 34 34 34),POLYGON((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),MULTIPOLYGON(((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)),((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0))),MULTILINESTRING((10 10 0,20 10 0,20 20 0,20 10 0,10 10 0),(5 5 0,5 6 0,6 6 0,6 5 0,5 5 0)))" }, | |
112 | { ALL,// new (correct) representation | |
113 | "GEOMETRYCOLLECTION EMPTY" }, | |
114 | }; | |
115 | ||
116 | private static JtsBinaryParser jtsBinaryParser = new JtsBinaryParser(); | |
117 | ||
118 | private static final JtsBinaryWriter jtsBinaryWriter = new JtsBinaryWriter(); | |
119 | ||
120 | private Connection connection = null; | |
121 | ||
122 | private Statement statement = null; | |
123 | ||
124 | ||
125 | @Test | |
126 | public void test() throws Exception { | |
127 | for (String[] aTestset : testset) { | |
128 | test(aTestset[1], aTestset[0]); | |
129 | test(SRIDPREFIX + aTestset[1], aTestset[0]); | |
130 | } | |
131 | } | |
132 | ||
133 | ||
134 | public void test(String WKT, String flags) throws SQLException { | |
135 | logger.debug("Original: {}", WKT); | |
136 | Geometry geom = JtsGeometry.geomFromString(WKT); | |
137 | String parsed = geom.toString(); | |
138 | if (WKT.startsWith("SRID=")) { | |
139 | parsed = "SRID=" + geom.getSRID() + ";" + parsed; | |
140 | } | |
141 | logger.debug("Parsed: {}", parsed); | |
142 | Geometry regeom = JtsGeometry.geomFromString(parsed); | |
143 | String reparsed = regeom.toString(); | |
144 | if (WKT.startsWith("SRID=")) { | |
145 | reparsed = "SRID=" + geom.getSRID() + ";" + reparsed; | |
146 | } | |
147 | logger.debug("Re-Parsed: {}", reparsed); | |
148 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
149 | Assert.assertEquals(geom.getSRID(), regeom.getSRID(), "Geometry SRIDs are not equal"); | |
150 | Assert.assertEquals(reparsed, parsed, "Text Reps are not equal"); | |
151 | ||
152 | String hexNWKT = jtsBinaryWriter.writeHexed(geom, ValueSetter.NDR.NUMBER); | |
153 | logger.debug("NDRHex: {}", hexNWKT); | |
154 | regeom = JtsGeometry.geomFromString(hexNWKT); | |
155 | logger.debug("ReNDRHex: {}", regeom); | |
156 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
157 | ||
158 | String hexXWKT = jtsBinaryWriter.writeHexed(geom, ValueSetter.XDR.NUMBER); | |
159 | logger.debug("XDRHex: {}", hexXWKT); | |
160 | regeom = JtsGeometry.geomFromString(hexXWKT); | |
161 | logger.debug("ReXDRHex: {}", regeom); | |
162 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
163 | ||
164 | byte[] NWKT = jtsBinaryWriter.writeBinary(geom, ValueSetter.NDR.NUMBER); | |
165 | regeom = jtsBinaryParser.parse(NWKT); | |
166 | logger.debug("NDR: {}", regeom); | |
167 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
168 | ||
169 | byte[] XWKT = jtsBinaryWriter.writeBinary(geom, ValueSetter.XDR.NUMBER); | |
170 | regeom = jtsBinaryParser.parse(XWKT); | |
171 | logger.debug("XDR: {}", regeom); | |
172 | Assert.assertEquals(geom, regeom, "Geometries are not equal"); | |
173 | ||
174 | Geometry coordArrayGeom = rebuildCS(geom); | |
175 | logger.debug("CoordArray: {}", regeom); | |
176 | Assert.assertEquals(geom, coordArrayGeom, "Geometries are not equal"); | |
177 | ||
178 | String coordArrayWKT = jtsBinaryWriter.writeHexed(coordArrayGeom, ValueSetter.NDR.NUMBER); | |
179 | logger.debug("HexCArray: {}", coordArrayWKT); | |
180 | Assert.assertEquals(coordArrayWKT, hexNWKT, "CoordArray HexWKT is not equal"); | |
181 | ||
182 | int serverPostgisMajor = getPostgisMajor(); | |
183 | ||
184 | if ((flags.equals(ONLY10)) && serverPostgisMajor < 1) { | |
185 | logger.info("PostGIS server too old, skipping test on connection {}", connection.getCatalog()); | |
186 | } else { | |
187 | logger.debug("Testing on connection {}", connection.getCatalog()); | |
188 | ||
189 | Geometry sqlGeom = viaSQL(WKT, statement); | |
190 | logger.debug("SQLin: {}", sqlGeom.toString()); | |
191 | if (!geom.equalsExact(sqlGeom)) { | |
192 | logger.warn("Geometries after SQL are not equal"); | |
193 | if (flags.equals(EQUAL10) && serverPostgisMajor < 1) { | |
194 | logger.info("This is expected with PostGIS {}.X", serverPostgisMajor); | |
195 | } else { | |
196 | Assert.fail(); | |
197 | } | |
198 | } | |
199 | ||
200 | Geometry sqlreGeom = viaSQL(parsed, statement); | |
201 | logger.debug("SQLout: {}", sqlreGeom); | |
202 | if (!geom.equalsExact(sqlreGeom)) { | |
203 | logger.warn("Reparsed Geometries after SQL are not equal"); | |
204 | if (flags.equals(EQUAL10) && serverPostgisMajor < 1) { | |
205 | logger.info("This is expected with PostGIS {}.X", serverPostgisMajor); | |
206 | } else { | |
207 | Assert.fail(); | |
208 | } | |
209 | } | |
210 | ||
211 | sqlreGeom = viaPrepSQL(geom, connection); | |
212 | logger.debug("Prepared: {}", sqlreGeom); | |
213 | if (!geom.equalsExact(sqlreGeom)) { | |
214 | logger.debug("Reparsed Geometries after prepared StatementSQL are not equal"); | |
215 | if (flags.equals(EQUAL10) && serverPostgisMajor < 1) { | |
216 | logger.info("This is expected with PostGIS {}.X", serverPostgisMajor); | |
217 | } else { | |
218 | Assert.fail(); | |
219 | } | |
220 | } | |
221 | ||
222 | // asEWKT() function is not present on PostGIS 0.X, and the test | |
223 | // is pointless as 0.X uses EWKT as canonical rep so the same | |
224 | // functionality was already tested above. | |
225 | if (serverPostgisMajor >= 1) { | |
226 | sqlGeom = ewktViaSQL(WKT, statement); | |
227 | logger.debug("asEWKT: {}", sqlGeom); | |
228 | Assert.assertEquals(geom, sqlGeom); | |
229 | ||
230 | sqlGeom = ewkbViaSQL(WKT, statement); | |
231 | logger.debug("asEWKB: {}", sqlGeom); | |
232 | Assert.assertEquals(geom, sqlGeom); | |
233 | ||
234 | sqlGeom = viaSQL(hexNWKT, statement); | |
235 | logger.debug("hexNWKT: {}", sqlGeom); | |
236 | Assert.assertEquals(geom, sqlGeom); | |
237 | ||
238 | sqlGeom = viaSQL(hexXWKT, statement); | |
239 | logger.debug("hexXWKT: {}", sqlGeom); | |
240 | Assert.assertEquals(geom, sqlGeom); | |
241 | ||
242 | sqlGeom = binaryViaSQL(NWKT, connection); | |
243 | logger.debug("NWKT: {}", sqlGeom); | |
244 | Assert.assertEquals(geom, sqlGeom); | |
245 | ||
246 | sqlGeom = binaryViaSQL(XWKT, connection); | |
247 | logger.debug("XWKT: {}", sqlGeom); | |
248 | Assert.assertEquals(geom, sqlGeom); | |
249 | } | |
250 | } | |
251 | } | |
252 | ||
253 | ||
254 | /** Pass a geometry representation through the SQL server */ | |
255 | private static Geometry viaSQL(String rep, Statement stat) throws SQLException { | |
256 | ResultSet rs = stat.executeQuery("SELECT geometry_in('" + rep + "')"); | |
257 | rs.next(); | |
258 | return ((JtsGeometry) rs.getObject(1)).getGeometry(); | |
259 | } | |
260 | ||
261 | ||
262 | /** | |
263 | * Pass a geometry representation through the SQL server via prepared | |
264 | * statement | |
265 | */ | |
266 | private static Geometry viaPrepSQL(Geometry geom, Connection conn) throws SQLException { | |
267 | PreparedStatement prep = conn.prepareStatement("SELECT ?::geometry"); | |
268 | JtsGeometry wrapper = new JtsGeometry(geom); | |
269 | prep.setObject(1, wrapper, Types.OTHER); | |
270 | ResultSet rs = prep.executeQuery(); | |
271 | rs.next(); | |
272 | JtsGeometry resultwrapper = ((JtsGeometry) rs.getObject(1)); | |
273 | return resultwrapper.getGeometry(); | |
274 | } | |
275 | ||
276 | ||
277 | /** Pass a geometry representation through the SQL server via EWKT */ | |
278 | private static Geometry ewktViaSQL(String rep, Statement stat) throws SQLException { | |
279 | ResultSet rs = stat.executeQuery("SELECT ST_AsEWKT(geometry_in('" + rep + "'))"); | |
280 | rs.next(); | |
281 | String resrep = rs.getString(1); | |
282 | return JtsGeometry.geomFromString(resrep); | |
283 | } | |
284 | ||
285 | ||
286 | /** Pass a geometry representation through the SQL server via EWKB */ | |
287 | private static Geometry ewkbViaSQL(String rep, Statement stat) throws SQLException { | |
288 | ResultSet rs = stat.executeQuery("SELECT ST_AsEWKB(geometry_in('" + rep + "'))"); | |
289 | rs.next(); | |
290 | byte[] resrep = rs.getBytes(1); | |
291 | return jtsBinaryParser.parse(resrep); | |
292 | } | |
293 | ||
294 | ||
295 | /** Pass a EWKB geometry representation through the server */ | |
296 | private static Geometry binaryViaSQL(byte[] rep, Connection conn) throws SQLException { | |
297 | PreparedStatement prep = conn.prepareStatement("SELECT ?::bytea::geometry"); | |
298 | prep.setBytes(1, rep); | |
299 | ResultSet rs = prep.executeQuery(); | |
300 | rs.next(); | |
301 | JtsGeometry resultwrapper = ((JtsGeometry) rs.getObject(1)); | |
302 | return resultwrapper.getGeometry(); | |
303 | } | |
304 | ||
305 | ||
306 | // Rebuild given Geometry with a CoordinateArraySequence implementation. | |
307 | public static Geometry rebuildCS(Geometry geom) { | |
308 | if (geom instanceof Point) { | |
309 | return rebuildCSPoint((Point)geom); | |
310 | } else if (geom instanceof MultiPoint) { | |
311 | return rebuildCSMP((MultiPoint)geom); | |
312 | } else if (geom instanceof LineString) { | |
313 | return rebuildCSLS((LineString)geom); | |
314 | } else if (geom instanceof MultiLineString) { | |
315 | return rebuildCSMLS((MultiLineString)geom); | |
316 | } else if (geom instanceof Polygon) { | |
317 | return rebuildCSP((Polygon)geom); | |
318 | } else if (geom instanceof MultiPolygon) { | |
319 | return rebuildCSMP((MultiPolygon)geom); | |
320 | } else if (geom instanceof GeometryCollection) { | |
321 | return rebuildCSGC((GeometryCollection)geom); | |
322 | } else { | |
323 | throw new AssertionError(); | |
324 | } | |
325 | } | |
326 | ||
327 | ||
328 | private static Point rebuildCSPoint(Point point) { | |
329 | Point result = point.getFactory().createPoint(point.getCoordinate()); | |
330 | result.setSRID(point.getSRID()); | |
331 | return result; | |
332 | } | |
333 | ||
334 | ||
335 | private static MultiPoint rebuildCSMP(MultiPoint mp) { | |
336 | Point[] points = new Point[mp.getNumGeometries()]; | |
337 | for (int i=0; i < points.length; i++) { | |
338 | points[i] = rebuildCSPoint((Point) mp.getGeometryN(i)); | |
339 | } | |
340 | MultiPoint result = mp.getFactory().createMultiPoint(points); | |
341 | result.setSRID(mp.getSRID()); | |
342 | return result; | |
343 | } | |
344 | ||
345 | ||
346 | private static MultiPolygon rebuildCSMP(MultiPolygon multipoly) { | |
347 | Polygon[] polygons = new Polygon[multipoly.getNumGeometries()]; | |
348 | for (int i=0; i < polygons.length; i++) { | |
349 | polygons[i] = rebuildCSP((Polygon)multipoly.getGeometryN(i)); | |
350 | } | |
351 | MultiPolygon result = multipoly.getFactory().createMultiPolygon(polygons); | |
352 | result.setSRID(multipoly.getSRID()); | |
353 | return result; | |
354 | } | |
355 | ||
356 | ||
357 | private static LineString rebuildCSLS(LineString line) { | |
358 | LineString result = line.getFactory().createLineString(line.getCoordinates()); | |
359 | result.setSRID(line.getSRID()); | |
360 | return result; | |
361 | } | |
362 | ||
363 | ||
364 | private static MultiLineString rebuildCSMLS(MultiLineString multiline) { | |
365 | LineString[] polygons = new LineString[multiline.getNumGeometries()]; | |
366 | for (int i=0; i < polygons.length; i++) { | |
367 | polygons[i] = rebuildCSLS((LineString)multiline.getGeometryN(i)); | |
368 | } | |
369 | MultiLineString result = multiline.getFactory().createMultiLineString(polygons); | |
370 | result.setSRID(multiline.getSRID()); | |
371 | return result; | |
372 | ||
373 | } | |
374 | ||
375 | ||
376 | private static Polygon rebuildCSP(Polygon polygon) { | |
377 | LinearRing outer = rebuildLR(polygon.getExteriorRing()); | |
378 | LinearRing[] holes = new LinearRing[polygon.getNumInteriorRing()]; | |
379 | for (int i=0; i < holes.length; i++) { | |
380 | holes[i] = rebuildLR(polygon.getInteriorRingN(i)); | |
381 | } | |
382 | Polygon result = polygon.getFactory().createPolygon(outer, holes); | |
383 | result.setSRID(polygon.getSRID()); | |
384 | return result; | |
385 | } | |
386 | ||
387 | ||
388 | private static LinearRing rebuildLR(LineString ring) { | |
389 | LinearRing result = ring.getFactory().createLinearRing(ring.getCoordinates()); | |
390 | result.setSRID(ring.getSRID()); | |
391 | return result; | |
392 | } | |
393 | ||
394 | ||
395 | private static Geometry rebuildCSGC(GeometryCollection coll) { | |
396 | Geometry[] geoms = new Geometry[coll.getNumGeometries()]; | |
397 | for (int i = 0; i < coll.getNumGeometries(); i++) { | |
398 | geoms[i] = rebuildCS(coll.getGeometryN(i)); | |
399 | } | |
400 | Geometry result = coll.getFactory().createGeometryCollection(geoms); | |
401 | result.setSRID(coll.getSRID()); | |
402 | return result; | |
403 | } | |
404 | ||
405 | ||
406 | public int getPostgisMajor() throws SQLException { | |
407 | ResultSet resultSet = statement.executeQuery("SELECT postgis_version()"); | |
408 | resultSet.next(); | |
409 | String version = resultSet.getString(1); | |
410 | if (version == null) { | |
411 | throw new SQLException("postgis_version returned NULL!"); | |
412 | } | |
413 | version = version.trim(); | |
414 | int idx = version.indexOf('.'); | |
415 | return Integer.parseInt(version.substring(0, idx)); | |
416 | } | |
417 | ||
418 | ||
419 | @BeforeClass | |
420 | public void initJdbcConnection(ITestContext ctx) throws Exception { | |
421 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
422 | Assert.assertNotNull(jdbcUrlSuffix); | |
423 | final String jdbcUrl = "jdbc:postgres_jts" + jdbcUrlSuffix; | |
424 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
425 | Assert.assertNotNull(jdbcUsername); | |
426 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
427 | Assert.assertNotNull(jdbcPassword); | |
428 | Class.forName(JTS_WRAPPER_CLASS_NAME); | |
429 | connection = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword); | |
430 | statement = connection.createStatement(); | |
431 | } | |
432 | ||
433 | ||
434 | @AfterClass | |
435 | public void unallocateDatabaseResources() throws Exception { | |
436 | if ((statement != null) && (!statement.isClosed())) { | |
437 | statement.close(); | |
438 | } | |
439 | if ((connection != null) && (!connection.isClosed())) { | |
440 | connection.close(); | |
441 | } | |
442 | } | |
443 | ||
444 | ||
445 | }⏎ |
0 | <configuration debug="false"> | |
1 | ||
2 | <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | |
3 | <layout class="ch.qos.logback.classic.PatternLayout"> | |
4 | <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> | |
5 | </layout> | |
6 | </appender> | |
7 | ||
8 | <root level="debug"> | |
9 | <appender-ref ref="STDOUT" /> | |
10 | </root> | |
11 | ||
12 | <logger name="com.github.dockerjava" level="ERROR"/> | |
13 | <logger name="org.testcontainers" level="ERROR"/> | |
14 | <logger name="net.postgis" level="ERROR"/> | |
15 | ||
16 | <logger name="net.postgis.jdbc.jts" level="ERROR"/> | |
17 | ||
18 | </configuration>⏎ |
0 | <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> | |
1 | <suite name="JTS Parser Integration Test Suite" verbose="1"> | |
2 | ||
3 | <parameter name="test.container.image-name" value="${test.container.image}"/> | |
4 | <parameter name="test.container.port" value="${test.db.port}"/> | |
5 | <parameter name="test.container.env.user" value="${test.db.username}"/> | |
6 | <parameter name="test.container.env.password" value="${test.db.password}"/> | |
7 | <parameter name="test.container.env.db" value="${test.db.name}"/> | |
8 | ||
9 | <test name="JTS Parser Integration Tests"> | |
10 | <classes> | |
11 | <class name="net.postgis.tools.testutils.TestContainerController"/> | |
12 | <class name="net.postgis.jdbc.jts.JtsParserTest"/> | |
13 | </classes> | |
14 | </test> | |
15 | ||
16 | </suite>⏎ |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
2 | <modelVersion>4.0.0</modelVersion> | |
3 | ||
4 | <parent> | |
5 | <artifactId>tools</artifactId> | |
6 | <groupId>net.postgis</groupId> | |
7 | <version>2.5.0</version> | |
8 | </parent> | |
9 | ||
10 | <artifactId>osgeo-postgis-jdbc-test-util</artifactId> | |
11 | <version>2.5.0</version> | |
12 | <packaging>jar</packaging> | |
13 | ||
14 | <name>osgeo-postgis-jdbc-test-util</name> | |
15 | <description> | |
16 | Simple smoke test util for verifying functionality postgis jdbc jar against a postgresql database with posgis | |
17 | extensions on OSGeo-Live. | |
18 | </description> | |
19 | ||
20 | <properties> | |
21 | <testTablePrefix>SMOKE_TEST</testTablePrefix> | |
22 | </properties> | |
23 | ||
24 | <dependencies> | |
25 | <dependency> | |
26 | <groupId>net.postgis</groupId> | |
27 | <artifactId>postgis-jdbc</artifactId> | |
28 | <version>2.5.0</version> | |
29 | </dependency> | |
30 | <dependency> | |
31 | <groupId>ch.qos.logback</groupId> | |
32 | <artifactId>logback-classic</artifactId> | |
33 | <version>${dependency.logback.version}</version> | |
34 | </dependency> | |
35 | <dependency> | |
36 | <groupId>ch.qos.logback</groupId> | |
37 | <artifactId>logback-core</artifactId> | |
38 | <version>${dependency.logback.version}</version> | |
39 | </dependency> | |
40 | <dependency> | |
41 | <groupId>net.postgis.tools</groupId> | |
42 | <artifactId>test-utils</artifactId> | |
43 | <version>2.5.0</version> | |
44 | <scope>test</scope> | |
45 | </dependency> | |
46 | </dependencies> | |
47 | ||
48 | <build> | |
49 | <testResources> | |
50 | <testResource> | |
51 | <directory>src/test/resources</directory> | |
52 | </testResource> | |
53 | <testResource> | |
54 | <directory>src/test/resources-filtered</directory> | |
55 | <filtering>true</filtering> | |
56 | </testResource> | |
57 | </testResources> | |
58 | <plugins> | |
59 | <plugin> | |
60 | <groupId>org.apache.maven.plugins</groupId> | |
61 | <artifactId>maven-failsafe-plugin</artifactId> | |
62 | <executions> | |
63 | <execution> | |
64 | <id>integration-tests</id> | |
65 | <goals> | |
66 | <goal>integration-test</goal> | |
67 | <goal>verify</goal> | |
68 | </goals> | |
69 | <configuration> | |
70 | <skip>${maven.integration.test.skip}</skip> | |
71 | <suiteXmlFiles> | |
72 | <suiteXmlFile>${project.build.testOutputDirectory}/testng-it.xml</suiteXmlFile> | |
73 | </suiteXmlFiles> | |
74 | </configuration> | |
75 | </execution> | |
76 | </executions> | |
77 | </plugin> | |
78 | <plugin> | |
79 | <groupId>org.apache.maven.plugins</groupId> | |
80 | <artifactId>maven-shade-plugin</artifactId> | |
81 | <executions> | |
82 | <execution> | |
83 | <id>shade</id> | |
84 | <phase>package</phase> | |
85 | <goals> | |
86 | <goal>shade</goal> | |
87 | </goals> | |
88 | <configuration> | |
89 | <artifactSet> | |
90 | <excludes> | |
91 | <exclude>net.postgis:postgis-jdbc</exclude> | |
92 | </excludes> | |
93 | </artifactSet> | |
94 | <transformers> | |
95 | <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> | |
96 | <mainClass>net.postgis.osgeo.util.Main</mainClass> | |
97 | </transformer> | |
98 | </transformers> | |
99 | </configuration> | |
100 | </execution> | |
101 | </executions> | |
102 | </plugin> | |
103 | <plugin> | |
104 | <groupId>org.apache.maven.plugins</groupId> | |
105 | <artifactId>maven-surefire-plugin</artifactId> | |
106 | <configuration> | |
107 | <skip>true</skip> | |
108 | </configuration> | |
109 | </plugin> | |
110 | </plugins> | |
111 | </build> | |
112 | ||
113 | </project>⏎ |
0 | package net.postgis.osgeo.util; | |
1 | ||
2 | import org.postgis.PGbox3d; | |
3 | import org.postgis.PGgeometry; | |
4 | import org.slf4j.Logger; | |
5 | import org.slf4j.LoggerFactory; | |
6 | ||
7 | import java.sql.Connection; | |
8 | import java.sql.DatabaseMetaData; | |
9 | import java.sql.DriverManager; | |
10 | import java.sql.ResultSet; | |
11 | import java.sql.SQLException; | |
12 | import java.sql.Statement; | |
13 | import java.util.Objects; | |
14 | import java.util.UUID; | |
15 | ||
16 | ||
17 | /** | |
18 | * Simple smoke test util for verifying functionality postgis jdbc jar against a postgresql database | |
19 | * with posgis extensions on OSGeo-Live. | |
20 | * | |
21 | * @author Phillip Ross | |
22 | */ | |
23 | public class Main { | |
24 | ||
25 | private static final Logger logger = LoggerFactory.getLogger(Main.class); | |
26 | ||
27 | private static final String DEFAULT_TEST_TABLE_PREFIX = "SMOKE_TEST"; | |
28 | ||
29 | private static final String JDBC_DRIVER_CLASS_NAME = "org.postgresql.Driver"; | |
30 | ||
31 | private Connection connection = null; | |
32 | ||
33 | private Statement statement = null; | |
34 | ||
35 | private String testTableName = null; | |
36 | ||
37 | ||
38 | public Main(final String jdbcUrl, | |
39 | final String jdbcUsername, | |
40 | final String jdbcPassword, | |
41 | final String testTablePrefix) { | |
42 | try { | |
43 | Objects.requireNonNull(jdbcUrl, "A JDBC URL must be specified"); | |
44 | Objects.requireNonNull(jdbcUsername, "A database username must be specified."); | |
45 | Objects.requireNonNull(jdbcPassword, "A database password must be specified."); | |
46 | Objects.requireNonNull(testTablePrefix, "Unable to determine test table prefix"); | |
47 | logger.debug("Running test (url/u/p/ttp): {}/{}/{}/{}", jdbcUrl, jdbcUsername, jdbcPassword, testTablePrefix); | |
48 | setupDatabaseResources(jdbcUrl, jdbcUsername, jdbcPassword); | |
49 | Objects.requireNonNull(connection, "Unable to continue testing without a connection to the database"); | |
50 | if (testDatatypeRegistration()) { | |
51 | Objects.requireNonNull(statement, "Unable to continue testing without a statement resource"); | |
52 | if (createTestTable(testTablePrefix)) { | |
53 | if (testSQL()) { | |
54 | logger.debug("All tests passed"); | |
55 | dropTestTable(); | |
56 | } | |
57 | } | |
58 | } | |
59 | closeDatabaseResources(); | |
60 | } catch (Exception e) { | |
61 | logger.error("Caught exception: {} {}", e.getClass().getName(), e.getMessage()); | |
62 | e.printStackTrace(); | |
63 | } | |
64 | } | |
65 | ||
66 | ||
67 | private boolean testSQL() { | |
68 | final String insertPointSQL = "insert into " + testTableName + " values ('POINT (10 10 10)',1)"; | |
69 | final String insertPolygonSQL = "insert into " + testTableName + " values ('POLYGON ((0 0 0,0 10 0,10 10 0,10 0 0,0 0 0))',2)"; | |
70 | ||
71 | boolean testPass = false; | |
72 | try { | |
73 | logger.debug("Inserting point..."); | |
74 | statement.execute(insertPointSQL); | |
75 | ||
76 | logger.debug("Inserting polygon..."); | |
77 | statement.execute(insertPolygonSQL); | |
78 | ||
79 | logger.debug("Querying table..."); | |
80 | ResultSet resultSet = statement.executeQuery("select ST_AsText(geom),id from " + testTableName); | |
81 | while (resultSet.next()) { | |
82 | Object obj = resultSet.getObject(1); | |
83 | int id = resultSet.getInt(2); | |
84 | logger.debug("Row {}: {}", id, obj.toString()); | |
85 | } | |
86 | testPass = true; | |
87 | } catch (SQLException se) { | |
88 | logger.error( | |
89 | "Caught SQLException attempting to issue SQL to the database: {} {}", | |
90 | se.getClass().getName(), | |
91 | se.getMessage() | |
92 | ); | |
93 | } | |
94 | return testPass; | |
95 | } | |
96 | ||
97 | ||
98 | private boolean createTestTable(final String testTablePrefix) { | |
99 | testTableName = testTablePrefix + "_" + UUID.randomUUID().toString().replaceAll("-", ""); | |
100 | final String dropSQL = "drop table " + testTableName; | |
101 | final String createSQL = "create table " + testTableName + " (geom geometry, id int4)"; | |
102 | ||
103 | boolean testPass = false; | |
104 | logger.debug("Creating table with geometric types..."); | |
105 | boolean tableExists = false; | |
106 | try { | |
107 | DatabaseMetaData databaseMetaData = connection.getMetaData(); | |
108 | try (ResultSet resultSet = databaseMetaData.getTables(null, null, testTableName.toLowerCase(), new String[] {"TABLE"})) { | |
109 | while (resultSet.next()) { | |
110 | tableExists = true; | |
111 | } | |
112 | } | |
113 | if (tableExists) { | |
114 | statement.execute(dropSQL); | |
115 | } | |
116 | statement.execute(createSQL); | |
117 | testPass = true; | |
118 | } catch (SQLException se) { | |
119 | logger.error( | |
120 | "Caught SQLException attempting to create the test table: {} {}", | |
121 | se.getClass().getName(), | |
122 | se.getMessage() | |
123 | ); | |
124 | } | |
125 | return testPass; | |
126 | } | |
127 | ||
128 | ||
129 | private void dropTestTable() { | |
130 | final String dropSQL = "drop table " + testTableName; | |
131 | logger.debug("Dropping test table"); | |
132 | boolean tableExists = false; | |
133 | try { | |
134 | DatabaseMetaData databaseMetaData = connection.getMetaData(); | |
135 | try (ResultSet resultSet = databaseMetaData.getTables(null, null, testTableName.toLowerCase(), new String[] {"TABLE"})) { | |
136 | while (resultSet.next()) { | |
137 | tableExists = true; | |
138 | } | |
139 | } | |
140 | if (tableExists) { | |
141 | statement.execute(dropSQL); | |
142 | } | |
143 | } catch (SQLException se) { | |
144 | logger.error( | |
145 | "Caught SQLException attempting to drop the test table: {} {}", | |
146 | se.getClass().getName(), | |
147 | se.getMessage() | |
148 | ); | |
149 | } | |
150 | } | |
151 | ||
152 | ||
153 | private boolean testDatatypeRegistration() { | |
154 | boolean testPass = false; | |
155 | logger.debug("Adding geometric type entries..."); | |
156 | try { | |
157 | ((org.postgresql.PGConnection)connection).addDataType("geometry", PGgeometry.class); | |
158 | ((org.postgresql.PGConnection)connection).addDataType("box3d", PGbox3d.class); | |
159 | testPass = true; | |
160 | } catch (SQLException se) { | |
161 | logger.error( | |
162 | "Caught SQLException attempting to register datatypes with PostgreSQL driver: {} {}", | |
163 | se.getClass().getName(), | |
164 | se.getMessage() | |
165 | ); | |
166 | } | |
167 | return testPass; | |
168 | } | |
169 | ||
170 | ||
171 | private void closeDatabaseResources() { | |
172 | try { | |
173 | if (statement != null) { | |
174 | statement.close(); | |
175 | } | |
176 | } catch (SQLException se) { | |
177 | logger.error( | |
178 | "Caught SQLException attempting to close statement resource: {} {}", | |
179 | se.getClass().getName(), | |
180 | se.getMessage() | |
181 | ); | |
182 | } | |
183 | try { | |
184 | if (connection != null) { | |
185 | connection.close(); | |
186 | } | |
187 | } catch (SQLException se) { | |
188 | logger.error( | |
189 | "Caught SQLException attempting to close connection to the database: {} {}", | |
190 | se.getClass().getName(), | |
191 | se.getMessage() | |
192 | ); | |
193 | } | |
194 | } | |
195 | ||
196 | ||
197 | private void setupDatabaseResources(final String url, final String username, final String password) { | |
198 | try { | |
199 | Class.forName(JDBC_DRIVER_CLASS_NAME); | |
200 | } catch (ClassNotFoundException e) { | |
201 | logger.error("Caught exception attempting to load jdbc driver class {}", JDBC_DRIVER_CLASS_NAME); | |
202 | logger.error("Check your classpath to verify that you've included the postgresql jdbc driver."); | |
203 | } | |
204 | try { | |
205 | connection = DriverManager.getConnection(url, username, password); | |
206 | statement = connection.createStatement(); | |
207 | } catch (SQLException se) { | |
208 | logger.error( | |
209 | "Caught SQLException attempting to setup database resources: {} {}", | |
210 | se.getClass().getName(), | |
211 | se.getMessage() | |
212 | ); | |
213 | } | |
214 | } | |
215 | ||
216 | ||
217 | public static void main(final String[] args) { | |
218 | if (args.length < 3) { | |
219 | System.out.println("parameters: jdbcUrl jdbcUsername jdbcPassword [testTablePrefix]"); | |
220 | } else { | |
221 | String jdbcUrl = args[0]; | |
222 | String jdbcUsername = args[1]; | |
223 | String jdbcPassword = args[2]; | |
224 | String testTablePrefix = DEFAULT_TEST_TABLE_PREFIX; | |
225 | if (args.length > 3) { | |
226 | testTablePrefix = args[3]; | |
227 | } | |
228 | new Main(jdbcUrl, jdbcUsername, jdbcPassword, testTablePrefix); | |
229 | } | |
230 | } | |
231 | ||
232 | ||
233 | } | |
234 | ||
235 | // java -classpath ~/.m2/repository/net/postgis/postgis-jdbc/2.2.1-SNAPSHOT/postgis-jdbc-2.2.1-SNAPSHOT.jar:target/osgeo-postgis-jdbc-test-util-0.0.1-SNAPSHOT.jar net.postgis.osgeo.util.Main jdbc:postgresql://db01:5432/postgis1 postgis1 postgis1 smoke_test |
0 | #!/usr/bin/env bash | |
1 | ||
2 | # The following sets variables based in command arguments | |
3 | TEST_JAR="${1}" # This should be the postgis-jdbc jar file to be tested. | |
4 | DB_HOSTNAME_AND_PORT=${2} # This should be the hostname:port of the database | |
5 | DB_USERNAME=${3} # This should be the database user to login as. | |
6 | DB_PASSWORD=${4} # This should be the database password to be used during login. | |
7 | ||
8 | # The following can be changed to point to the jar containing the test utility. By default it | |
9 | # points to a jar file in a local maven repository. | |
10 | MVN_REPO_LOCATION=~/.m2/repository | |
11 | GROUP_ID_DIR=/net/postgis | |
12 | TEST_UTIL_JAR=${MVN_REPO_LOCATION}${GROUP_ID_DIR}/osgeo-postgis-jdbc-test-util/0.0.1-SNAPSHOT/osgeo-postgis-jdbc-test-util-0.0.1-SNAPSHOT.jar | |
13 | ||
14 | # The following variables are derived from the variables above. | |
15 | # They are used to invoke the JVM with the test utility. | |
16 | JDBC_URL="jdbc:postgresql://${DB_HOSTNAME_AND_PORT}/postgis1" | |
17 | JDBC_USERNAME=${DB_USERNAME} | |
18 | JDBC_PASSWORD=${DB_PASSWORD} | |
19 | ||
20 | # The exactly commandline used to invoke the utility is output before it is actually invoked. | |
21 | echo "==> java -classpath ${TEST_JAR}:${TEST_UTIL_JAR} net.postgis.osgeo.util.Main ${JDBC_URL} ${JDBC_USERNAME} ${JDBC_PASSWORD}" | |
22 | ||
23 | java -classpath ${TEST_JAR}:${TEST_UTIL_JAR} net.postgis.osgeo.util.Main ${JDBC_URL} ${JDBC_USERNAME} ${JDBC_PASSWORD}⏎ |
+0
-33
0 | package net.postgis.osgeo.util; | |
1 | ||
2 | import net.postgis.tools.testutils.TestContainerController; | |
3 | import org.slf4j.Logger; | |
4 | import org.slf4j.LoggerFactory; | |
5 | import org.testng.Assert; | |
6 | import org.testng.ITestContext; | |
7 | import org.testng.annotations.Test; | |
8 | ||
9 | ||
10 | /** | |
11 | * A test class for testing the primary utility. | |
12 | * | |
13 | * @author Phillip Ross | |
14 | */ | |
15 | public class UtilTest { | |
16 | ||
17 | private static final Logger logger = LoggerFactory.getLogger(UtilTest.class); | |
18 | ||
19 | ||
20 | @Test | |
21 | public void test(ITestContext ctx) { | |
22 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
23 | Assert.assertNotNull(jdbcUrlSuffix); | |
24 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
25 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
26 | Assert.assertNotNull(jdbcUsername); | |
27 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
28 | Main.main(new String[] {jdbcUrl, jdbcUsername, jdbcPassword}); | |
29 | } | |
30 | ||
31 | ||
32 | } |
0 | <configuration debug="false"> | |
1 | ||
2 | <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | |
3 | <layout class="ch.qos.logback.classic.PatternLayout"> | |
4 | <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> | |
5 | </layout> | |
6 | </appender> | |
7 | ||
8 | <root level="debug"> | |
9 | <appender-ref ref="STDOUT" /> | |
10 | </root> | |
11 | ||
12 | <logger name="com.github.dockerjava" level="ERROR"/> | |
13 | <logger name="org.testcontainers" level="ERROR"/> | |
14 | <logger name="net.postgis" level="ERROR"/> | |
15 | ||
16 | <logger name="net.postgis.osgeo.util" level="DEBUG"/> | |
17 | ||
18 | </configuration>⏎ |
0 | <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> | |
1 | <suite name="OSGeo PostGIS JDBC Test Util Test Suite" verbose="1"> | |
2 | ||
3 | <parameter name="test.container.image-name" value="${test.container.image}"/> | |
4 | <parameter name="test.container.port" value="${test.db.port}"/> | |
5 | <parameter name="test.container.env.user" value="${test.db.username}"/> | |
6 | <parameter name="test.container.env.password" value="${test.db.password}"/> | |
7 | <parameter name="test.container.env.db" value="${test.db.name}"/> | |
8 | ||
9 | <test name="Util Integration Tests"> | |
10 | <classes> | |
11 | <class name="net.postgis.tools.testutils.TestContainerController"/> | |
12 | <class name="net.postgis.osgeo.util.UtilTest" /> | |
13 | </classes> | |
14 | </test> | |
15 | ||
16 | </suite> |
4 | 4 | <parent> |
5 | 5 | <artifactId>postgis-java-aggregator</artifactId> |
6 | 6 | <groupId>net.postgis</groupId> |
7 | <version>2.5.0</version> | |
7 | <version>2021.1.0</version> | |
8 | 8 | </parent> |
9 | 9 | |
10 | 10 | <artifactId>tools</artifactId> |
11 | <version>2.5.0</version> | |
11 | <version>2021.1.0</version> | |
12 | 12 | <packaging>pom</packaging> |
13 | 13 | |
14 | 14 | <name>Tools</name> |
15 | 15 | <description>Miscellaneous tools and utilities</description> |
16 | 16 | |
17 | 17 | <modules> |
18 | <module>osgeo-postgis-jdbc-test-util</module> | |
18 | <module>smoketest</module> | |
19 | 19 | <module>test-utils</module> |
20 | 20 | </modules> |
21 | 21 |
0 | dependency-reduced-pom.xml |
0 | <?xml version="1.0" encoding="UTF-8"?> | |
1 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
2 | <modelVersion>4.0.0</modelVersion> | |
3 | ||
4 | <parent> | |
5 | <artifactId>tools</artifactId> | |
6 | <groupId>net.postgis</groupId> | |
7 | <version>2021.1.0</version> | |
8 | </parent> | |
9 | ||
10 | <artifactId>smoketest</artifactId> | |
11 | <version>2021.1.0</version> | |
12 | <packaging>jar</packaging> | |
13 | ||
14 | <name>smoketest</name> | |
15 | <description> | |
16 | Simple smoke test util for verifying functionality postgis jdbc jar against a postgresql database with posgis | |
17 | extensions on OSGeo-Live. | |
18 | </description> | |
19 | ||
20 | <properties> | |
21 | <testTablePrefix>SMOKE_TEST</testTablePrefix> | |
22 | </properties> | |
23 | ||
24 | <dependencies> | |
25 | <dependency> | |
26 | <groupId>net.postgis</groupId> | |
27 | <artifactId>postgis-jdbc</artifactId> | |
28 | <version>2021.1.0</version> | |
29 | </dependency> | |
30 | <dependency> | |
31 | <groupId>net.postgis</groupId> | |
32 | <artifactId>postgis-jdbc-java2d</artifactId> | |
33 | <version>2021.1.0</version> | |
34 | </dependency> | |
35 | <dependency> | |
36 | <groupId>ch.qos.logback</groupId> | |
37 | <artifactId>logback-classic</artifactId> | |
38 | <version>${dependency.logback.version}</version> | |
39 | </dependency> | |
40 | <dependency> | |
41 | <groupId>ch.qos.logback</groupId> | |
42 | <artifactId>logback-core</artifactId> | |
43 | <version>${dependency.logback.version}</version> | |
44 | </dependency> | |
45 | <dependency> | |
46 | <groupId>net.postgis.tools</groupId> | |
47 | <artifactId>test-utils</artifactId> | |
48 | <version>2021.1.0</version> | |
49 | <scope>test</scope> | |
50 | </dependency> | |
51 | </dependencies> | |
52 | ||
53 | <build> | |
54 | <testResources> | |
55 | <testResource> | |
56 | <directory>src/test/resources</directory> | |
57 | </testResource> | |
58 | <testResource> | |
59 | <directory>src/test/resources-filtered</directory> | |
60 | <filtering>true</filtering> | |
61 | </testResource> | |
62 | </testResources> | |
63 | <plugins> | |
64 | <plugin> | |
65 | <groupId>org.apache.maven.plugins</groupId> | |
66 | <artifactId>maven-failsafe-plugin</artifactId> | |
67 | <executions> | |
68 | <execution> | |
69 | <id>integration-tests</id> | |
70 | <goals> | |
71 | <goal>integration-test</goal> | |
72 | <goal>verify</goal> | |
73 | </goals> | |
74 | <configuration> | |
75 | <skip>${maven.integration.test.skip}</skip> | |
76 | <suiteXmlFiles> | |
77 | <suiteXmlFile>${project.build.testOutputDirectory}/testng-it.xml</suiteXmlFile> | |
78 | </suiteXmlFiles> | |
79 | </configuration> | |
80 | </execution> | |
81 | </executions> | |
82 | </plugin> | |
83 | <plugin> | |
84 | <groupId>org.apache.maven.plugins</groupId> | |
85 | <artifactId>maven-shade-plugin</artifactId> | |
86 | <executions> | |
87 | <execution> | |
88 | <id>shade</id> | |
89 | <phase>package</phase> | |
90 | <goals> | |
91 | <goal>shade</goal> | |
92 | </goals> | |
93 | <configuration> | |
94 | <artifactSet> | |
95 | <excludes> | |
96 | <exclude>net.postgis:postgis-jdbc</exclude> | |
97 | </excludes> | |
98 | </artifactSet> | |
99 | <transformers> | |
100 | <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> | |
101 | <mainClass>net.postgis.jdbc.smoketest.OSGeo</mainClass> | |
102 | </transformer> | |
103 | </transformers> | |
104 | </configuration> | |
105 | </execution> | |
106 | </executions> | |
107 | </plugin> | |
108 | <plugin> | |
109 | <groupId>org.apache.maven.plugins</groupId> | |
110 | <artifactId>maven-surefire-plugin</artifactId> | |
111 | <configuration> | |
112 | <skip>true</skip> | |
113 | </configuration> | |
114 | </plugin> | |
115 | </plugins> | |
116 | </build> | |
117 | ||
118 | </project>⏎ |
0 | /* | |
1 | * TestAutoregister.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
6 | * | |
7 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | ||
25 | package net.postgis.jdbc.smoketest; | |
26 | ||
27 | import net.postgis.jdbc.PGbox2d; | |
28 | import net.postgis.jdbc.PGbox3d; | |
29 | import net.postgis.jdbc.PGgeometry; | |
30 | import org.postgresql.Driver; | |
31 | import org.postgresql.util.PGobject; | |
32 | ||
33 | import java.sql.Connection; | |
34 | import java.sql.DriverManager; | |
35 | import java.sql.ResultSet; | |
36 | import java.sql.SQLException; | |
37 | import java.sql.Statement; | |
38 | ||
39 | /** | |
40 | * This test program tests whether the autoregistration of PostGIS data types | |
41 | * within the pgjdbc driver was successful. This is supposed to work with | |
42 | * pgjdbc.jar version 8.0 and newer, and thus refuses to work with older pgjdbc | |
43 | * versions. (But it will work fine against older servers.) It also checks for | |
44 | * postgis version to know whether box2d is available. | |
45 | */ | |
46 | public class Autoregister { | |
47 | ||
48 | public static void main(String[] args) { | |
49 | String dburl = null; | |
50 | String dbuser = null; | |
51 | String dbpass = null; | |
52 | ||
53 | if (args.length == 3) { | |
54 | System.out.println("Testing proper auto-registration"); | |
55 | dburl = args[0]; | |
56 | dbuser = args[1]; | |
57 | dbpass = args[2]; | |
58 | } else { | |
59 | System.err.println("Usage: java examples/TestParser dburl user pass"); | |
60 | System.exit(1); | |
61 | // Signal the compiler that code flow ends here. | |
62 | return; | |
63 | } | |
64 | ||
65 | System.out.println("Driver version: " + Driver.getVersion()); | |
66 | int major; | |
67 | try { | |
68 | major = new Driver().getMajorVersion(); | |
69 | } catch (Exception e) { | |
70 | System.err.println("Cannot create Driver instance: " + e.getMessage()); | |
71 | System.exit(1); | |
72 | return; | |
73 | } | |
74 | ||
75 | if (major < 8) { | |
76 | System.err.println("Your pgdjbc " + major | |
77 | + ".X is too old, it does not support autoregistration!"); | |
78 | return; | |
79 | } | |
80 | ||
81 | System.out.println("Creating JDBC connection to " + dburl); | |
82 | Connection conn = null; | |
83 | Statement stat = null; | |
84 | try { | |
85 | conn = DriverManager.getConnection(dburl, dbuser, dbpass); | |
86 | stat = conn.createStatement(); | |
87 | } catch (SQLException e) { | |
88 | System.err.println("Connection initialization failed, aborting."); | |
89 | e.printStackTrace(); | |
90 | System.exit(1); | |
91 | // signal the compiler that code flow ends here: | |
92 | throw new AssertionError(); | |
93 | } | |
94 | ||
95 | int postgisServerMajor = 0; | |
96 | try { | |
97 | postgisServerMajor = getPostgisMajor(stat); | |
98 | } catch (SQLException e) { | |
99 | System.err.println("Error fetching PostGIS version: " + e.getMessage()); | |
100 | System.err.println("Is PostGIS really installed in the database?"); | |
101 | System.exit(1); | |
102 | // signal the compiler that code flow ends here: | |
103 | throw new AssertionError(); | |
104 | } | |
105 | ||
106 | System.out.println("PostGIS Version: " + postgisServerMajor); | |
107 | ||
108 | PGobject result = null; | |
109 | ||
110 | /* Test geometries */ | |
111 | try { | |
112 | ResultSet rs = stat.executeQuery("SELECT 'POINT(1 2)'::geometry"); | |
113 | rs.next(); | |
114 | result = (PGobject) rs.getObject(1); | |
115 | if (result instanceof PGgeometry) { | |
116 | System.out.println("PGgeometry successful!"); | |
117 | } else { | |
118 | System.out.println("PGgeometry failed!"); | |
119 | } | |
120 | } catch (SQLException e) { | |
121 | System.err.println("Selecting geometry failed: " + e.getMessage()); | |
122 | System.exit(1); | |
123 | // Signal the compiler that code flow ends here. | |
124 | return; | |
125 | } | |
126 | ||
127 | /* Test box3d */ | |
128 | try { | |
129 | ResultSet rs = stat.executeQuery("SELECT 'BOX3D(1 2 3, 4 5 6)'::box3d"); | |
130 | rs.next(); | |
131 | result = (PGobject) rs.getObject(1); | |
132 | if (result instanceof PGbox3d) { | |
133 | System.out.println("Box3d successful!"); | |
134 | } else { | |
135 | System.out.println("Box3d failed!"); | |
136 | } | |
137 | } catch (SQLException e) { | |
138 | System.err.println("Selecting box3d failed: " + e.getMessage()); | |
139 | System.exit(1); | |
140 | // Signal the compiler that code flow ends here. | |
141 | return; | |
142 | } | |
143 | ||
144 | /* Test box2d if appropriate */ | |
145 | if (postgisServerMajor < 1) { | |
146 | System.out.println("PostGIS version is too old, skipping box2ed test"); | |
147 | System.err.println("PostGIS version is too old, skipping box2ed test"); | |
148 | } else { | |
149 | try { | |
150 | ResultSet rs = stat.executeQuery("SELECT 'BOX(1 2,3 4)'::box2d"); | |
151 | rs.next(); | |
152 | result = (PGobject) rs.getObject(1); | |
153 | if (result instanceof PGbox2d) { | |
154 | System.out.println("Box2d successful!"); | |
155 | } else { | |
156 | System.out.println("Box2d failed! " + result.getClass().getName()); | |
157 | } | |
158 | } catch (SQLException e) { | |
159 | System.err.println("Selecting box2d failed: " + e.getMessage()); | |
160 | System.exit(1); | |
161 | // Signal the compiler that code flow ends here. | |
162 | return; | |
163 | } | |
164 | } | |
165 | ||
166 | System.out.println("Finished."); | |
167 | // If we finished up to here without exitting, we passed all tests. | |
168 | System.err.println("TestAutoregister.java finished without errors."); | |
169 | } | |
170 | ||
171 | public static int getPostgisMajor(Statement stat) throws SQLException { | |
172 | ResultSet rs = stat.executeQuery("SELECT postgis_version()"); | |
173 | rs.next(); | |
174 | String version = rs.getString(1); | |
175 | if (version == null) { | |
176 | throw new SQLException("postgis_version returned NULL!"); | |
177 | } | |
178 | version = version.trim(); | |
179 | int idx = version.indexOf('.'); | |
180 | return Integer.parseInt(version.substring(0, idx)); | |
181 | } | |
182 | } |
0 | /* | |
1 | * TestJava2d.java | |
2 | * | |
3 | * PostGIS extension for PostgreSQL JDBC driver - example and test classes | |
4 | * | |
5 | * (C) 2004 Paul Ramsey, pramsey@refractions.net | |
6 | * | |
7 | * (C) 2005 Markus Schaber, markus.schaber@logix-tt.com | |
8 | * | |
9 | * (C) 2015 Phillip Ross, phillip.w.g.ross@gmail.com | |
10 | * | |
11 | * This library is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU Lesser General Public | |
13 | * License as published by the Free Software Foundation; either | |
14 | * version 2.1 of the License, or (at your option) any later version. | |
15 | * | |
16 | * This library is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * Lesser General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU Lesser General Public | |
22 | * License along with this library; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
24 | * | |
25 | */ | |
26 | ||
27 | package net.postgis.jdbc.smoketest; | |
28 | ||
29 | import java.awt.*; | |
30 | import java.awt.event.WindowEvent; | |
31 | import java.awt.event.WindowListener; | |
32 | import java.awt.geom.AffineTransform; | |
33 | import java.awt.geom.Rectangle2D; | |
34 | import java.sql.Connection; | |
35 | import java.sql.DriverManager; | |
36 | import java.sql.ResultSet; | |
37 | import java.sql.SQLException; | |
38 | import java.util.ArrayList; | |
39 | ||
40 | import net.postgis.jdbc.java2d.Java2DWrapper; | |
41 | ||
42 | public class Java2d { | |
43 | private static final boolean DEBUG = true; | |
44 | ||
45 | public static final Shape[] SHAPEARRAY = new Shape[0]; | |
46 | ||
47 | public static final String[][] testDataset = new String[][] { | |
48 | {"point1", "POINT(10 11)"}, | |
49 | {"multipoint1", "MULTIPOINT(10.25 11,10.5 11,10.75 11,11 11,11.25 11,11.5 11,11.75 11,12 11)"}, | |
50 | {"linestring1", "LINESTRING(0 0,100 0,100 100,0 100)"}, | |
51 | {"linestring2", "LINESTRING(-310 110,210 110,210 210,-310 210,-310 110)"}, | |
52 | {"multilinestring", "MULTILINESTRING((0 0,10 10,20 0,30 10),(40 0,40 10,50 10,50 20,60 20))"}, | |
53 | }; | |
54 | ||
55 | static { | |
56 | new Java2DWrapper(); // make shure our driver is initialized | |
57 | } | |
58 | ||
59 | public static void main(String[] args) throws ClassNotFoundException, SQLException { | |
60 | ||
61 | if (args.length != 5) { | |
62 | System.err.println("Usage: java examples/TestJava2D dburl user pass tablename column"); | |
63 | System.err.println(); | |
64 | System.err.println("dburl has the following format:"); | |
65 | System.err.println(Java2DWrapper.POSTGIS_PROTOCOL + "//HOST:PORT/DATABASENAME"); | |
66 | System.err.println("tablename is 'jdbc_test' by default."); | |
67 | System.exit(1); | |
68 | } | |
69 | ||
70 | Shape[] geometries = read(args[0], args[1], args[2], "SELECT " + args[4] + " FROM " + args[3]); | |
71 | if (DEBUG) { | |
72 | System.err.println("read " + geometries.length + " geometries."); | |
73 | } | |
74 | if (geometries.length == 0) { | |
75 | if (DEBUG) { | |
76 | System.err.println("No geometries were read."); | |
77 | } | |
78 | return; | |
79 | } | |
80 | ||
81 | System.err.println("Painting..."); | |
82 | Frame window = new Frame("PostGIS java2D demo"); | |
83 | ||
84 | Canvas CV = new GisCanvas(geometries); | |
85 | ||
86 | window.add(CV); | |
87 | ||
88 | window.setSize(500, 500); | |
89 | ||
90 | window.addWindowListener(new EventHandler()); | |
91 | ||
92 | window.setVisible(true); | |
93 | } | |
94 | ||
95 | static Rectangle2D calcbbox(Shape[] geometries) { | |
96 | Rectangle2D bbox = geometries[0].getBounds2D(); | |
97 | for (int i = 1; i < geometries.length; i++) { | |
98 | bbox = bbox.createUnion(geometries[i].getBounds2D()); | |
99 | } | |
100 | return bbox; | |
101 | } | |
102 | ||
103 | private static Shape[] read(String dburl, String dbuser, String dbpass, String query) | |
104 | throws ClassNotFoundException, SQLException { | |
105 | ArrayList geometries = new ArrayList(); | |
106 | if (DEBUG) { | |
107 | System.err.println("Creating JDBC connection..."); | |
108 | } | |
109 | Class.forName("org.postgresql.Driver"); | |
110 | Connection conn = DriverManager.getConnection(dburl, dbuser, dbpass); | |
111 | ||
112 | if (DEBUG) { | |
113 | System.err.println("fetching geometries: " + query); | |
114 | } | |
115 | ResultSet r = conn.createStatement().executeQuery(query); | |
116 | ||
117 | while (r.next()) { | |
118 | final Shape current = (Shape) r.getObject(1); | |
119 | if (current != null) { | |
120 | geometries.add(current); | |
121 | } | |
122 | } | |
123 | conn.close(); | |
124 | return (Shape[]) geometries.toArray(SHAPEARRAY); | |
125 | } | |
126 | ||
127 | public static class GisCanvas extends Canvas { | |
128 | /** Keep java 1.5 compiler happy */ | |
129 | private static final long serialVersionUID = 1L; | |
130 | ||
131 | final Rectangle2D bbox; | |
132 | final Shape[] geometries; | |
133 | ||
134 | public GisCanvas(Shape[] geometries) { | |
135 | this.geometries = geometries; | |
136 | this.bbox = calcbbox(geometries); | |
137 | setBackground(Color.GREEN); | |
138 | } | |
139 | ||
140 | public void paint(Graphics og) { | |
141 | Graphics2D g = (Graphics2D) og; | |
142 | // Add 5% padding on all borders | |
143 | final double paddingTop = bbox.getHeight() * 0.05; | |
144 | final double paddingBottom = bbox.getHeight() * 0.05; | |
145 | final double paddingLeft = bbox.getWidth() * 0.05; | |
146 | final double paddingRight = bbox.getWidth() * 0.05; | |
147 | // If the bounding box has negative coordinates, we need to offset by the negative coordinate | |
148 | final double offsetX = (bbox.getX() < 0) ? (0 - bbox.getX()) : 0; | |
149 | final double offsetY = (bbox.getY() < 0) ? (0 - bbox.getY()) : 0; | |
150 | // Scale by the bounding box and padding | |
151 | final double scaleX = (super.getWidth() - (paddingLeft + paddingRight)) / (bbox.getWidth()); | |
152 | final double scaleY = (super.getHeight() - (paddingTop + paddingBottom)) / (bbox.getHeight()); | |
153 | // Apply the transform parameters | |
154 | AffineTransform at = new AffineTransform(); | |
155 | at.translate(paddingLeft, paddingTop); | |
156 | at.scale(scaleX, scaleY); | |
157 | at.translate(offsetX, offsetY); | |
158 | ||
159 | if (DEBUG) { | |
160 | System.err.println(); | |
161 | System.err.println("paddingTop: " + paddingTop); | |
162 | System.err.println("paddingBottom: " + paddingBottom); | |
163 | System.err.println("paddingLeft: " + paddingLeft); | |
164 | System.err.println("paddingRight: " + paddingRight); | |
165 | System.err.println("offsetX: " + offsetX); | |
166 | System.err.println("offsetY: " + offsetY); | |
167 | System.err.println("scaleX: " + scaleX); | |
168 | System.err.println("scaleY: " + scaleY); | |
169 | System.err.println("bbox: " + bbox); | |
170 | System.err.println("trans: " + at); | |
171 | System.err.println("new: " + at.createTransformedShape(bbox).getBounds2D()); | |
172 | System.err.println("visual:" + super.getBounds()); | |
173 | } | |
174 | for (int i = 0; i < geometries.length; i++) { | |
175 | g.setPaint(Color.BLUE); | |
176 | final Shape shape = at.createTransformedShape(geometries[i]); | |
177 | g.fill(shape); | |
178 | g.setPaint(Color.ORANGE); | |
179 | g.draw(shape); | |
180 | } | |
181 | } | |
182 | } | |
183 | ||
184 | public static class EventHandler implements WindowListener { | |
185 | ||
186 | public void windowActivated(WindowEvent e) {// | |
187 | } | |
188 | ||
189 | public void windowClosed(WindowEvent e) {// | |
190 | } | |
191 | ||
192 | public void windowClosing(WindowEvent e) { | |
193 | e.getWindow().setVisible(false); | |
194 | System.exit(0); | |
195 | } | |
196 | ||
197 | public void windowDeactivated(WindowEvent e) {// | |
198 | } | |
199 | ||
200 | public void windowDeiconified(WindowEvent e) {// | |
201 | } | |
202 | ||
203 | public void windowIconified(WindowEvent e) {// | |
204 | } | |
205 | ||
206 | public void windowOpened(WindowEvent e) {// | |
207 | } | |
208 | } | |
209 | }⏎ |
0 | package net.postgis.jdbc.smoketest; | |
1 | ||
2 | import net.postgis.jdbc.PGbox3d; | |
3 | import net.postgis.jdbc.PGgeometry; | |
4 | import org.slf4j.Logger; | |
5 | import org.slf4j.LoggerFactory; | |
6 | ||
7 | import java.sql.Connection; | |
8 | import java.sql.DatabaseMetaData; | |
9 | import java.sql.DriverManager; | |
10 | import java.sql.ResultSet; | |
11 | import java.sql.SQLException; | |
12 | import java.sql.Statement; | |
13 | import java.util.Objects; | |
14 | import java.util.UUID; | |
15 | ||
16 | ||
17 | /** | |
18 | * Simple smoke test util for verifying functionality postgis jdbc jar against a postgresql database | |
19 | * with posgis extensions on OSGeo-Live. | |
20 | * | |
21 | * @author Phillip Ross | |
22 | */ | |
23 | public class OSGeo { | |
24 | ||
25 | private static final Logger logger = LoggerFactory.getLogger(OSGeo.class); | |
26 | ||
27 | private static final String DEFAULT_TEST_TABLE_PREFIX = "SMOKE_TEST"; | |
28 | ||
29 | private static final String JDBC_DRIVER_CLASS_NAME = "org.postgresql.Driver"; | |
30 | ||
31 | private Connection connection = null; | |
32 | ||
33 | private Statement statement = null; | |
34 | ||
35 | private String testTableName = null; | |
36 | ||
37 | ||
38 | public OSGeo(final String jdbcUrl, | |
39 | final String jdbcUsername, | |
40 | final String jdbcPassword, | |
41 | final String testTablePrefix) { | |
42 | try { | |
43 | Objects.requireNonNull(jdbcUrl, "A JDBC URL must be specified"); | |
44 | Objects.requireNonNull(jdbcUsername, "A database username must be specified."); | |
45 | Objects.requireNonNull(jdbcPassword, "A database password must be specified."); | |
46 | Objects.requireNonNull(testTablePrefix, "Unable to determine test table prefix"); | |
47 | logger.debug("Running test (url/u/p/ttp): {}/{}/{}/{}", jdbcUrl, jdbcUsername, jdbcPassword, testTablePrefix); | |
48 | setupDatabaseResources(jdbcUrl, jdbcUsername, jdbcPassword); | |
49 | Objects.requireNonNull(connection, "Unable to continue testing without a connection to the database"); | |
50 | if (testDatatypeRegistration()) { | |
51 | Objects.requireNonNull(statement, "Unable to continue testing without a statement resource"); | |
52 | if (createTestTable(testTablePrefix)) { | |
53 | if (testSQL()) { | |
54 | logger.debug("All tests passed"); | |
55 | dropTestTable(); | |
56 | } | |
57 | } | |
58 | } | |
59 | closeDatabaseResources(); | |
60 | } catch (Exception e) { | |
61 | logger.error("Caught exception: {} {}", e.getClass().getName(), e.getMessage()); | |
62 | e.printStackTrace(); | |
63 | } | |
64 | } | |
65 | ||
66 | ||
67 | private boolean testSQL() { | |
68 | final String insertPointSQL = "insert into " + testTableName + " values ('POINT (10 10 10)',1)"; | |
69 | final String insertPolygonSQL = "insert into " + testTableName + " values ('POLYGON ((0 0 0,0 10 0,10 10 0,10 0 0,0 0 0))',2)"; | |
70 | ||
71 | boolean testPass = false; | |
72 | try { | |
73 | logger.debug("Inserting point..."); | |
74 | statement.execute(insertPointSQL); | |
75 | ||
76 | logger.debug("Inserting polygon..."); | |
77 | statement.execute(insertPolygonSQL); | |
78 | ||
79 | logger.debug("Querying table..."); | |
80 | ResultSet resultSet = statement.executeQuery("select ST_AsText(geom),id from " + testTableName); | |
81 | while (resultSet.next()) { | |
82 | Object obj = resultSet.getObject(1); | |
83 | int id = resultSet.getInt(2); | |
84 | logger.debug("Row {}: {}", id, obj.toString()); | |
85 | } | |
86 | testPass = true; | |
87 | } catch (SQLException se) { | |
88 | logger.error( | |
89 | "Caught SQLException attempting to issue SQL to the database: {} {}", | |
90 | se.getClass().getName(), | |
91 | se.getMessage() | |
92 | ); | |
93 | } | |
94 | return testPass; | |
95 | } | |
96 | ||
97 | ||
98 | private boolean createTestTable(final String testTablePrefix) { | |
99 | testTableName = testTablePrefix + "_" + UUID.randomUUID().toString().replaceAll("-", ""); | |
100 | final String dropSQL = "drop table " + testTableName; | |
101 | final String createSQL = "create table " + testTableName + " (geom geometry, id int4)"; | |
102 | ||
103 | boolean testPass = false; | |
104 | logger.debug("Creating table with geometric types..."); | |
105 | boolean tableExists = false; | |
106 | try { | |
107 | DatabaseMetaData databaseMetaData = connection.getMetaData(); | |
108 | try (ResultSet resultSet = databaseMetaData.getTables(null, null, testTableName.toLowerCase(), new String[] {"TABLE"})) { | |
109 | while (resultSet.next()) { | |
110 | tableExists = true; | |
111 | } | |
112 | } | |
113 | if (tableExists) { | |
114 | statement.execute(dropSQL); | |
115 | } | |
116 | statement.execute(createSQL); | |
117 | testPass = true; | |
118 | } catch (SQLException se) { | |
119 | logger.error( | |
120 | "Caught SQLException attempting to create the test table: {} {}", | |
121 | se.getClass().getName(), | |
122 | se.getMessage() | |
123 | ); | |
124 | } | |
125 | return testPass; | |
126 | } | |
127 | ||
128 | ||
129 | private void dropTestTable() { | |
130 | final String dropSQL = "drop table " + testTableName; | |
131 | logger.debug("Dropping test table"); | |
132 | boolean tableExists = false; | |
133 | try { | |
134 | DatabaseMetaData databaseMetaData = connection.getMetaData(); | |
135 | try (ResultSet resultSet = databaseMetaData.getTables(null, null, testTableName.toLowerCase(), new String[] {"TABLE"})) { | |
136 | while (resultSet.next()) { | |
137 | tableExists = true; | |
138 | } | |
139 | } | |
140 | if (tableExists) { | |
141 | statement.execute(dropSQL); | |
142 | } | |
143 | } catch (SQLException se) { | |
144 | logger.error( | |
145 | "Caught SQLException attempting to drop the test table: {} {}", | |
146 | se.getClass().getName(), | |
147 | se.getMessage() | |
148 | ); | |
149 | } | |
150 | } | |
151 | ||
152 | ||
153 | private boolean testDatatypeRegistration() { | |
154 | boolean testPass = false; | |
155 | logger.debug("Adding geometric type entries..."); | |
156 | try { | |
157 | ((org.postgresql.PGConnection)connection).addDataType("geometry", PGgeometry.class); | |
158 | ((org.postgresql.PGConnection)connection).addDataType("box3d", PGbox3d.class); | |
159 | testPass = true; | |
160 | } catch (SQLException se) { | |
161 | logger.error( | |
162 | "Caught SQLException attempting to register datatypes with PostgreSQL driver: {} {}", | |
163 | se.getClass().getName(), | |
164 | se.getMessage() | |
165 | ); | |
166 | } | |
167 | return testPass; | |
168 | } | |
169 | ||
170 | ||
171 | private void closeDatabaseResources() { | |
172 | try { | |
173 | if (statement != null) { | |
174 | statement.close(); | |
175 | } | |
176 | } catch (SQLException se) { | |
177 | logger.error( | |
178 | "Caught SQLException attempting to close statement resource: {} {}", | |
179 | se.getClass().getName(), | |
180 | se.getMessage() | |
181 | ); | |
182 | } | |
183 | try { | |
184 | if (connection != null) { | |
185 | connection.close(); | |
186 | } | |
187 | } catch (SQLException se) { | |
188 | logger.error( | |
189 | "Caught SQLException attempting to close connection to the database: {} {}", | |
190 | se.getClass().getName(), | |
191 | se.getMessage() | |
192 | ); | |
193 | } | |
194 | } | |
195 | ||
196 | ||
197 | private void setupDatabaseResources(final String url, final String username, final String password) { | |
198 | try { | |
199 | Class.forName(JDBC_DRIVER_CLASS_NAME); | |
200 | } catch (ClassNotFoundException e) { | |
201 | logger.error("Caught exception attempting to load jdbc driver class {}", JDBC_DRIVER_CLASS_NAME); | |
202 | logger.error("Check your classpath to verify that you've included the postgresql jdbc driver."); | |
203 | } | |
204 | try { | |
205 | connection = DriverManager.getConnection(url, username, password); | |
206 | statement = connection.createStatement(); | |
207 | } catch (SQLException se) { | |
208 | logger.error( | |
209 | "Caught SQLException attempting to setup database resources: {} {}", | |
210 | se.getClass().getName(), | |
211 | se.getMessage() | |
212 | ); | |
213 | } | |
214 | } | |
215 | ||
216 | ||
217 | public static void main(final String[] args) { | |
218 | if (args.length < 3) { | |
219 | System.out.println("parameters: jdbcUrl jdbcUsername jdbcPassword [testTablePrefix]"); | |
220 | } else { | |
221 | String jdbcUrl = args[0]; | |
222 | String jdbcUsername = args[1]; | |
223 | String jdbcPassword = args[2]; | |
224 | String testTablePrefix = DEFAULT_TEST_TABLE_PREFIX; | |
225 | if (args.length > 3) { | |
226 | testTablePrefix = args[3]; | |
227 | } | |
228 | new OSGeo(jdbcUrl, jdbcUsername, jdbcPassword, testTablePrefix); | |
229 | } | |
230 | } | |
231 | ||
232 | ||
233 | } | |
234 | ||
235 | // java -classpath ~/.m2/repository/net/postgis/postgis-jdbc/2.2.1-SNAPSHOT/postgis-jdbc-2.2.1-SNAPSHOT.jar:target/smoketest-0.0.1-SNAPSHOT.jar net.postgis.osgeo.util.Main jdbc:postgresql://db01:5432/postgis1 postgis1 postgis1 smoke_test |
0 | #!/usr/bin/env bash | |
1 | ||
2 | # The following sets variables based in command arguments | |
3 | TEST_JAR="${1}" # This should be the postgis-jdbc jar file to be tested. | |
4 | DB_HOSTNAME_AND_PORT=${2} # This should be the hostname:port of the database | |
5 | DB_USERNAME=${3} # This should be the database user to login as. | |
6 | DB_PASSWORD=${4} # This should be the database password to be used during login. | |
7 | ||
8 | # The following can be changed to point to the jar containing the test utility. By default it | |
9 | # points to a jar file in a local maven repository. | |
10 | MVN_REPO_LOCATION=~/.m2/repository | |
11 | GROUP_ID_DIR=/net/postgis | |
12 | TEST_UTIL_JAR=${MVN_REPO_LOCATION}${GROUP_ID_DIR}/smoketest/0.0.1-SNAPSHOT/smoketest-0.0.1-SNAPSHOT.jar | |
13 | ||
14 | # The following variables are derived from the variables above. | |
15 | # They are used to invoke the JVM with the test utility. | |
16 | JDBC_URL="jdbc:postgresql://${DB_HOSTNAME_AND_PORT}/postgis1" | |
17 | JDBC_USERNAME=${DB_USERNAME} | |
18 | JDBC_PASSWORD=${DB_PASSWORD} | |
19 | ||
20 | # The exactly commandline used to invoke the utility is output before it is actually invoked. | |
21 | echo "==> java -classpath ${TEST_JAR}:${TEST_UTIL_JAR} net.postgis.jdbc.smoketest.OSGeo ${JDBC_URL} ${JDBC_USERNAME} ${JDBC_PASSWORD}" | |
22 | ||
23 | java -classpath ${TEST_JAR}:${TEST_UTIL_JAR} net.postgis.osgeo.util.Main ${JDBC_URL} ${JDBC_USERNAME} ${JDBC_PASSWORD}⏎ |
0 | package net.postgis.jdbc.smoketest; | |
1 | ||
2 | import net.postgis.tools.testutils.TestContainerController; | |
3 | import org.slf4j.Logger; | |
4 | import org.slf4j.LoggerFactory; | |
5 | import org.testng.Assert; | |
6 | import org.testng.ITestContext; | |
7 | import org.testng.annotations.Test; | |
8 | ||
9 | ||
10 | /** | |
11 | * A test class for testing the primary utility. | |
12 | * | |
13 | * @author Phillip Ross | |
14 | */ | |
15 | public class UtilTest { | |
16 | ||
17 | private static final Logger logger = LoggerFactory.getLogger(UtilTest.class); | |
18 | ||
19 | ||
20 | @Test | |
21 | public void test(ITestContext ctx) { | |
22 | final String jdbcUrlSuffix = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_JDBC_URL_SUFFIX); | |
23 | Assert.assertNotNull(jdbcUrlSuffix); | |
24 | final String jdbcUrl = "jdbc:postgresql" + jdbcUrlSuffix; | |
25 | final String jdbcUsername = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_USER_PARAM_NAME); | |
26 | Assert.assertNotNull(jdbcUsername); | |
27 | final String jdbcPassword = (String)ctx.getAttribute(TestContainerController.TEST_CONTAINER_ENV_PW_PARAM_NAME); | |
28 | OSGeo.main(new String[] {jdbcUrl, jdbcUsername, jdbcPassword}); | |
29 | } | |
30 | ||
31 | ||
32 | } |
0 | <configuration debug="false"> | |
1 | ||
2 | <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | |
3 | <layout class="ch.qos.logback.classic.PatternLayout"> | |
4 | <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> | |
5 | </layout> | |
6 | </appender> | |
7 | ||
8 | <root level="debug"> | |
9 | <appender-ref ref="STDOUT" /> | |
10 | </root> | |
11 | ||
12 | <logger name="com.github.dockerjava" level="ERROR"/> | |
13 | <logger name="org.testcontainers" level="ERROR"/> | |
14 | <logger name="net.postgis" level="ERROR"/> | |
15 | ||
16 | </configuration>⏎ |
0 | <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> | |
1 | <suite name="OSGeo PostGIS JDBC Test Util Test Suite" verbose="1"> | |
2 | ||
3 | <parameter name="test.container.image-name" value="${test.container.image}"/> | |
4 | <parameter name="test.container.port" value="${test.db.port}"/> | |
5 | <parameter name="test.container.env.user" value="${test.db.username}"/> | |
6 | <parameter name="test.container.env.password" value="${test.db.password}"/> | |
7 | <parameter name="test.container.env.db" value="${test.db.name}"/> | |
8 | ||
9 | <test name="Util Integration Tests"> | |
10 | <classes> | |
11 | <class name="net.postgis.tools.testutils.TestContainerController"/> | |
12 | <class name="net.postgis.jdbc.smoketest.UtilTest" /> | |
13 | </classes> | |
14 | </test> | |
15 | ||
16 | </suite> |
4 | 4 | <parent> |
5 | 5 | <groupId>net.postgis</groupId> |
6 | 6 | <artifactId>tools</artifactId> |
7 | <version>2.5.0</version> | |
7 | <version>2021.1.0</version> | |
8 | 8 | </parent> |
9 | 9 | |
10 | 10 | <groupId>net.postgis.tools</groupId> |
11 | 11 | <artifactId>test-utils</artifactId> |
12 | <version>2.5.0</version> | |
12 | <version>2021.1.0</version> | |
13 | 13 | |
14 | 14 | <name>Test Utilities</name> |
15 | 15 | <description>Tools to facilities building and maintaining test suites</description> |